diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..980d7f4
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,2 @@
+types
+node_modules
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..85b3eb0
--- /dev/null
+++ b/.eslintrc.js
@@ -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 }],
+ },
+};
diff --git a/.eslintrc.yml b/.eslintrc.yml
deleted file mode 100644
index ff96a83..0000000
--- a/.eslintrc.yml
+++ /dev/null
@@ -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
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..27ec51a
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,41 @@
+name: CI
+
+on:
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ code_quality:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout main repository
+ uses: actions/checkout@v3
+
+ - name: Clone ags-types to temp dir
+ uses: actions/checkout@v3
+ with:
+ repository: Jas-SinghFSU/ags-types
+ path: temp-ags-types
+
+ - name: Copy types to types/
+ run: |
+ rm -rf types
+ mkdir -p types
+ cp -R temp-ags-types/types/* types/
+ rm -rf temp-ags-types
+
+ - name: Node Setup
+ uses: actions/setup-node@v3
+ with:
+ node-version: '21'
+
+ - name: Install Dependencies
+ run: npm install
+
+ - name: ESLint
+ run: npm run lint
+
+ - name: Type Check
+ run: npx tsc --noEmit --pretty --extendedDiagnostics
diff --git a/.gitignore b/.gitignore
index 2458c1e..9144fba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
.weather.json
+node_modules
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..b165aa5
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "external/ags-types"]
+ path = external/ags-types
+ url = https://github.com/Jas-SinghFSU/ags-types.git
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..97843e6
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,2 @@
+.eslintrc.js
+types/**/*.ts
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..6e88f12
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,8 @@
+{
+ "singleQuote": true,
+ "semi": true,
+ "trailingComma": "all",
+ "printWidth": 120,
+ "tabWidth": 4,
+ "useTabs": false
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..75c0349
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Jas Singh
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 243ed20..b855cc5 100644
--- a/README.md
+++ b/README.md
@@ -11,21 +11,26 @@
# HyprPanel 🚀
+
A panel built for Hyprland with [AGS](https://github.com/Aylur/ags)

## Installation
+
The [HyprPanel Wiki](https://hyprpanel.com/getting_started/installation.html) contains in depth instructions for installing the panel and all of its dependencies. The instructions below are general instructions for installing the panel.
## Requirements
+
Bun
```sh
curl -fsSL https://bun.sh/install | bash && \
sudo ln -s $HOME/.bun/bin/bun /usr/local/bin/bun
```
+
Additional dependencies:
+
```sh
pipewire
libgtop
@@ -45,53 +50,110 @@ gnome-bluetooth-3.0
```
Optional Dependencies:
+
```sh
## Used for Tracking GPU Usage in your Dashboard (NVidia only)
python
python-gpustat
+
+## Only if a pywal hook from wallpaper changes applied through settings is desired
+pywal
+
+## To check for pacman updates in the default script used in the updates module
+pacman-contrib
+
+## To switch between power profiles in battery module
+power-profiles-daemon
```
-Arch (pacman):
+### Arch
+
+pacman:
```bash
-sudo pacman -S pipewire libgtop bluez bluez-utils btop networkmanager dart-sass wl-clipboard brightnessctl swww python gnome-bluetooth-3.0
+sudo pacman -S pipewire libgtop bluez bluez-utils btop networkmanager dart-sass wl-clipboard brightnessctl swww python gnome-bluetooth-3.0 pacman-contrib power-profiles-daemon
```
-Arch (AUR):
+AUR:
+
```bash
yay -S grimblast-git gpu-screen-recorder hyprpicker matugen-bin python-gpustat aylurs-gtk-shell-git
```
+### Fedora
+
+COPR - Add [solopasha/hyprland](https://copr.fedorainfracloud.org/coprs/solopasha/hyprland/) for most hyprland-related dependencies, and [hues-sueh/packages](https://copr.fedorainfracloud.org/coprs/heus-sueh/packages/) for matugen. Both provide the `swww` package, so prioritise the former repo:
+```bash
+sudo dnf copr enable solopasha/hyprland
+sudo dnf copr enable heus-sueh/packages
+sudo dnf config-manager --save --setopt=copr:copr.fedorainfracloud.org:heus-sueh:packages.priority=200
+```
+
+DNF:
+```bash
+sudo dnf install pipewire libgtop2 bluez bluez-tools grimblast hyprpicker btop NetworkManager wl-clipboard swww brightnessctl gnome-bluetooth aylurs-gtk-shell power-profiles-daemon gvfs
+```
+
+bun:
+```bash
+bun install -g sass
+```
+
+flatpak:
+```bash
+flatpak install flathub --system com.dec05eba.gpu_screen_recorder
+```
+
+#### Optional Dependencies
+
+pip:
+```bash
+sudo dnf install python python3-pip; pip install gpustat pywal
+```
+
+### NixOS
+
For NixOS/Home-Manager, see [NixOS & Home-Manager instructions](#nixos--home-manager).
## Instructions
### AGS
+
Once everything is installed you need to put the contents of this repo in `~/.config/ags`.
If you already have something in `~/.config/ags`, it's recommended that you back it up with:
+
```bash
mv $HOME/.config/ags $HOME/.config/ags.bkup
```
+
Otherwise you can use this command to install the panel:
+
```bash
git clone https://github.com/Jas-SinghFSU/HyprPanel.git && \
ln -s $(pwd)/HyprPanel $HOME/.config/ags
```
+
### Nerd Fonts
+
Additionally, you need to ensure that you have a [Nerd Font](https://www.nerdfonts.com/font-downloads) installed for your icons to render properly.
### Launch the panel
+
Afterwards you can run the panel with the following command in your terminal:
+
```bash
ags
```
Or you can add it to your Hyprland config (hyprland.conf) to auto-start with:
+
```bash
exec-once = ags
```
### NixOS & Home-Manager
+
Alternatively, if you're using NixOS and/or Home-Manager, you can setup AGS using the provided Nix Flake. First, add the repository to your Flake's inputs, and enable the overlay.
+
```nix
# flake.nix
@@ -99,7 +161,7 @@ Alternatively, if you're using NixOS and/or Home-Manager, you can setup AGS usin
inputs.hyprpanel.url = "github:Jas-SinghFSU/HyprPanel";
# ...
- outputs = { self, nixpkgs, ... }@inputs:
+ outputs = { self, nixpkgs, ... }@inputs:
let
# ...
system = "x86_64-linux"; # change to whatever your system should be.
@@ -169,6 +231,7 @@ The panel is automatically scaled based on your font size in `Configuration > Ge
### Specifying bar layouts per monitor
To specify layouts for each monitor you can create a JSON object such as:
+
```JSON
{
"0": {
@@ -223,19 +286,21 @@ To specify layouts for each monitor you can create a JSON object such as:
```
Where each monitor is defined by its index (0, 1, 2 in this case) and each section (left, middle, right) contains one or more of the following modules:
+
```js
-"battery"
-"dashboard"
-"workspaces"
-"windowtitle"
-"media"
-"notifications"
-"volume"
-"network"
-"bluetooth"
-"clock"
-"systray"
+'battery';
+'dashboard';
+'workspaces';
+'windowtitle';
+'media';
+'notifications';
+'volume';
+'network';
+'bluetooth';
+'clock';
+'systray';
```
+
Since the text-box in the options dialog isn't sufficient, it is recommended that you create this JSON configuration in a text editor elsewhere and paste it into the layout text-box under Configuration > Bar > "Bar Layouts for Monitors".
### Additional Configuration
diff --git a/config.js b/config.js
index 6417940..01d6ae8 100644
--- a/config.js
+++ b/config.js
@@ -1,46 +1,58 @@
-import GLib from "gi://GLib"
+import GLib from 'gi://GLib';
-const main = "/tmp/ags/hyprpanel/main.js"
-const entry = `${App.configDir}/main.ts`
-const bundler = GLib.getenv("AGS_BUNDLER") || "bun"
+const main = '/tmp/ags/hyprpanel/main.js';
+const entry = `${App.configDir}/main.ts`;
+const bundler = GLib.getenv('AGS_BUNDLER') || 'bun';
const v = {
- ags: pkg.version?.split(".").map(Number) || [],
+ ags: pkg.version?.split('.').map(Number) || [],
expect: [1, 8, 1],
-}
+};
try {
switch (bundler) {
- case "bun": await Utils.execAsync([
- "bun", "build", entry,
- "--outfile", main,
- "--external", "resource://*",
- "--external", "gi://*",
- "--external", "file://*",
- ]); break
+ case 'bun':
+ await Utils.execAsync([
+ 'bun',
+ 'build',
+ entry,
+ '--outfile',
+ main,
+ '--external',
+ 'resource://*',
+ '--external',
+ 'gi://*',
+ '--external',
+ 'file://*',
+ ]);
+ break;
- case "esbuild": await Utils.execAsync([
- "esbuild", "--bundle", entry,
- "--format=esm",
- `--outfile=${main}`,
- "--external:resource://*",
- "--external:gi://*",
- "--external:file://*",
- ]); break
+ case 'esbuild':
+ await Utils.execAsync([
+ 'esbuild',
+ '--bundle',
+ entry,
+ '--format=esm',
+ `--outfile=${main}`,
+ '--external:resource://*',
+ '--external:gi://*',
+ '--external:file://*',
+ ]);
+ break;
default:
- throw `"${bundler}" is not a valid bundler`
+ throw `"${bundler}" is not a valid bundler`;
}
if (v.ags[1] < v.expect[1] || v.ags[2] < v.expect[2]) {
- print(`HyprPanel needs atleast v${v.expect.join(".")} of AGS, yours is v${v.ags.join(".")}`)
- App.quit()
+ print(`HyprPanel needs atleast v${v.expect.join('.')} of AGS, yours is v${v.ags.join('.')}`);
+ App.quit();
}
- await import(`file://${main}`)
+ await import(`file://${main}`);
} catch (error) {
- console.error(error)
- App.quit()
+ console.error(error);
+ App.quit();
}
-export { }
+export {};
diff --git a/customModules/PollVar.ts b/customModules/PollVar.ts
index 620358e..2381e89 100644
--- a/customModules/PollVar.ts
+++ b/customModules/PollVar.ts
@@ -1,26 +1,25 @@
-import GLib from "gi://GLib?version=2.0";
-import { Binding } from "types/service";
-import { Variable as VariableType } from "types/variable";
-
-type GenericFunction = (...args: any[]) => any;
+import GLib from 'gi://GLib?version=2.0';
+import { GenericFunction } from 'lib/types/customModules/generic';
+import { Bind } from 'lib/types/variable';
+import { Variable as VariableType } from 'types/variable';
/**
* @param {VariableType} targetVariable - The Variable to update with the function's result.
- * @param {Array>} trackers - Array of trackers to watch.
- * @param {Binding} pollingInterval - The polling interval in milliseconds.
- * @param {GenericFunction} someFunc - The function to execute at each interval, which updates the Variable.
- * @param {...any} params - Parameters to pass to someFunc.
+ * @param {Array} trackers - Array of trackers to watch.
+ * @param {Bind} pollingInterval - The polling interval in milliseconds.
+ * @param {GenericFunction} someFunc - The function to execute at each interval, which updates the Variable.
+ * @param {...P} params - Parameters to pass to someFunc.
*/
-export const pollVariable = (
+export const pollVariable = >(
targetVariable: VariableType,
- trackers: Array>,
- pollingInterval: Binding,
- someFunc: GenericFunction,
- ...params: any[]
+ trackers: Array,
+ pollingInterval: Bind,
+ someFunc: F,
+ ...params: P
): void => {
let intervalInstance: number | null = null;
- const intervalFn = (pollIntrvl: number) => {
+ const intervalFn = (pollIntrvl: number): void => {
if (intervalInstance !== null) {
GLib.source_remove(intervalInstance);
}
@@ -37,39 +36,41 @@ export const pollVariable = (
/**
* @param {VariableType} targetVariable - The Variable to update with the result of the command.
- * @param {Binding} pollingInterval - The polling interval in milliseconds.
+ * @param {Array} trackers - Array of trackers to watch.
+ * @param {Bind} pollingInterval - The polling interval in milliseconds.
* @param {string} someCommand - The bash command to execute.
- * @param {GenericFunction} someFunc - The function to execute after processing the command result.
- * @param {...any} params - Parameters to pass to someFunc.
+ * @param {GenericFunction} someFunc - The function to execute after processing the command result;
+ * with the first argument being the result of the command execution.
+ * @param {...P} params - Additional parameters to pass to someFunc.
*/
-export const pollVariableBash = (
+export const pollVariableBash = >(
targetVariable: VariableType,
- trackers: Array>,
- pollingInterval: Binding,
+ trackers: Array,
+ pollingInterval: Bind,
someCommand: string,
- someFunc: (res: any, ...params: any[]) => T,
- ...params: any[]
+ someFunc: F,
+ ...params: P
): void => {
let intervalInstance: number | null = null;
- const intervalFn = (pollIntrvl: number) => {
+ const intervalFn = (pollIntrvl: number): void => {
if (intervalInstance !== null) {
GLib.source_remove(intervalInstance);
}
intervalInstance = Utils.interval(pollIntrvl, () => {
- Utils.execAsync(`bash -c "${someCommand}"`).then((res: any) => {
- try {
- targetVariable.value = someFunc(res, ...params);
- } catch (error) {
- console.warn(`An error occurred when running interval bash function: ${error}`);
- }
- })
+ Utils.execAsync(`bash -c "${someCommand}"`)
+ .then((res: string) => {
+ try {
+ targetVariable.value = someFunc(res, ...params);
+ } catch (error) {
+ console.warn(`An error occurred when running interval bash function: ${error}`);
+ }
+ })
.catch((err) => console.error(`Error running command "${someCommand}": ${err}`));
});
};
- // Set up the interval initially with the provided polling interval
Utils.merge([pollingInterval, ...trackers], (pollIntrvl: number) => {
intervalFn(pollIntrvl);
});
diff --git a/customModules/config.ts b/customModules/config.ts
index 3207500..5e72214 100644
--- a/customModules/config.ts
+++ b/customModules/config.ts
@@ -2,8 +2,10 @@ import { Option } from 'widget/settings/shared/Option';
import { Header } from 'widget/settings/shared/Header';
import options from 'options';
+import Scrollable from 'types/widgets/scrollable';
+import { Attribute, GtkWidget } from 'lib/types/widget';
-export const CustomModuleSettings = () =>
+export const CustomModuleSettings = (): Scrollable =>
Widget.Scrollable({
vscroll: 'automatic',
hscroll: 'automatic',
@@ -12,11 +14,11 @@ export const CustomModuleSettings = () =>
class_name: 'menu-theme-page paged-container',
vertical: true,
children: [
- /*
- ************************************
- * GENERAL *
- ************************************
- */
+ /*
+ ************************************
+ * GENERAL *
+ ************************************
+ */
Header('General'),
Option({
opt: options.bar.customModules.scrollSpeed,
@@ -24,11 +26,11 @@ export const CustomModuleSettings = () =>
type: 'number',
}),
- /*
- ************************************
- * RAM *
- ************************************
- */
+ /*
+ ************************************
+ * RAM *
+ ************************************
+ */
Header('RAM'),
Option({
opt: options.bar.customModules.ram.label,
@@ -75,11 +77,11 @@ export const CustomModuleSettings = () =>
type: 'string',
}),
- /*
- ************************************
- * CPU *
- ************************************
- */
+ /*
+ ************************************
+ * CPU *
+ ************************************
+ */
Header('CPU'),
Option({
opt: options.bar.customModules.cpu.label,
@@ -130,11 +132,11 @@ export const CustomModuleSettings = () =>
type: 'string',
}),
- /*
- ************************************
- * STORAGE *
- ************************************
- */
+ /*
+ ************************************
+ * STORAGE *
+ ************************************
+ */
Header('Storage'),
Option({
opt: options.bar.customModules.storage.icon,
@@ -187,11 +189,11 @@ export const CustomModuleSettings = () =>
type: 'string',
}),
- /*
- ************************************
- * NETSTAT *
- ************************************
- */
+ /*
+ ************************************
+ * NETSTAT *
+ ************************************
+ */
Header('Netstat'),
Option({
opt: options.bar.customModules.netstat.networkInterface,
@@ -204,17 +206,7 @@ export const CustomModuleSettings = () =>
opt: options.bar.customModules.netstat.icon,
title: 'Netstat Icon',
type: 'enum',
- enums: [
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- ],
+ enums: ['', '', '', '', '', '', '', '', ''],
}),
Option({
opt: options.bar.customModules.netstat.label,
@@ -267,11 +259,11 @@ export const CustomModuleSettings = () =>
type: 'string',
}),
- /*
- ************************************
- * KEYBOARD LAYOUT *
- ************************************
- */
+ /*
+ ************************************
+ * KEYBOARD LAYOUT *
+ ************************************
+ */
Header('Keyboard Layout'),
Option({
opt: options.bar.customModules.kbLayout.icon,
@@ -321,11 +313,11 @@ export const CustomModuleSettings = () =>
type: 'string',
}),
- /*
- ************************************
- * UPDATES *
- ************************************
- */
+ /*
+ ************************************
+ * UPDATES *
+ ************************************
+ */
Header('Updates'),
Option({
opt: options.bar.customModules.updates.updateCommand,
@@ -336,17 +328,7 @@ export const CustomModuleSettings = () =>
opt: options.bar.customModules.updates.icon,
title: 'Updates Icon',
type: 'enum',
- enums: [
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- ],
+ enums: ['', '', '', '', '', '', '', '', ''],
}),
Option({
opt: options.bar.customModules.updates.label,
@@ -367,7 +349,7 @@ export const CustomModuleSettings = () =>
opt: options.bar.customModules.updates.pollingInterval,
title: 'Polling Interval',
type: 'number',
- subtitle: "WARNING: Be careful of your package manager\'s rate limit.",
+ subtitle: "WARNING: Be careful of your package manager's rate limit.",
min: 100,
max: 60 * 24 * 1000,
increment: 1000,
@@ -398,11 +380,11 @@ export const CustomModuleSettings = () =>
type: 'string',
}),
- /*
- ************************************
- * WEATHER *
- ************************************
- */
+ /*
+ ************************************
+ * WEATHER *
+ ************************************
+ */
Header('Weather'),
Option({
opt: options.bar.customModules.weather.label,
@@ -446,11 +428,11 @@ export const CustomModuleSettings = () =>
type: 'string',
}),
- /*
- ************************************
- * POWER *
- ************************************
- */
+ /*
+ ************************************
+ * POWER *
+ ************************************
+ */
Header('Power'),
Option({
opt: options.theme.bar.buttons.modules.power.spacing,
@@ -491,4 +473,3 @@ export const CustomModuleSettings = () =>
],
}),
});
-
diff --git a/customModules/cpu/computeCPU.ts b/customModules/cpu/computeCPU.ts
index ef3542d..460b1db 100644
--- a/customModules/cpu/computeCPU.ts
+++ b/customModules/cpu/computeCPU.ts
@@ -1,12 +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';
-const defaultCpuData: number = 0;
-
let previousCpuData = new GTop.glibtop_cpu();
GTop.glibtop_get_cpu(previousCpuData);
-export const computeCPU = () => {
+export const computeCPU = (): number => {
const currentCpuData = new GTop.glibtop_cpu();
GTop.glibtop_get_cpu(currentCpuData);
@@ -19,5 +17,4 @@ export const computeCPU = () => {
previousCpuData = currentCpuData;
return cpuUsagePercentage;
-}
-
+};
diff --git a/customModules/cpu/index.ts b/customModules/cpu/index.ts
index d10b15e..1eb8ea7 100644
--- a/customModules/cpu/index.ts
+++ b/customModules/cpu/index.ts
@@ -1,31 +1,21 @@
-import options from "options";
-
-// @ts-expect-error
-import GTop from 'gi://GTop';
+import options from 'options';
// Module initializer
-import { module } from "../module"
+import { module } from '../module';
// import { CpuData } from "lib/types/customModules/cpu";
-import Button from "types/widgets/button";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
+import Button from 'types/widgets/button';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
// Utility Methods
-import { inputHandler } from "customModules/utils";
-import { computeCPU } from "./computeCPU";
-import { pollVariable } from "customModules/PollVar";
+import { inputHandler } from 'customModules/utils';
+import { computeCPU } from './computeCPU';
+import { pollVariable } from 'customModules/PollVar';
+import { Module } from 'lib/types/bar';
// All the user configurable options for the cpu module that are needed
-const {
- label,
- round,
- leftClick,
- rightClick,
- middleClick,
- scrollUp,
- scrollDown,
- pollingInterval
-} = options.bar.customModules.cpu;
+const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval } =
+ options.bar.customModules.cpu;
export const cpuUsage = Variable(0);
@@ -40,21 +30,19 @@ pollVariable(
computeCPU,
);
-export const Cpu = () => {
- const renderLabel = (cpuUsg: number, rnd: boolean) => {
+export const Cpu = (): Module => {
+ const renderLabel = (cpuUsg: number, rnd: boolean): string => {
return rnd ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`;
- }
+ };
const cpuModule = module({
- textIcon: "",
- label: Utils.merge(
- [cpuUsage.bind("value"), round.bind("value")],
- (cpuUsg, rnd) => {
- return renderLabel(cpuUsg, rnd);
- }),
- tooltipText: "CPU",
- boxClass: "cpu",
- showLabelBinding: label.bind("value"),
+ textIcon: '',
+ label: Utils.merge([cpuUsage.bind('value'), round.bind('value')], (cpuUsg, rnd) => {
+ return renderLabel(cpuUsg, rnd);
+ }),
+ tooltipText: 'CPU',
+ boxClass: 'cpu',
+ showLabelBinding: label.bind('value'),
props: {
setup: (self: Button) => {
inputHandler(self, {
@@ -75,9 +63,8 @@ export const Cpu = () => {
},
});
},
- }
+ },
});
return cpuModule;
-}
-
+};
diff --git a/customModules/kblayout/getLayout.ts b/customModules/kblayout/getLayout.ts
index 97a27ec..9c42071 100644
--- a/customModules/kblayout/getLayout.ts
+++ b/customModules/kblayout/getLayout.ts
@@ -1,12 +1,18 @@
-import { HyprctlDeviceLayout, HyprctlKeyboard, KbLabelType } from "lib/types/customModules/kbLayout";
-import { layoutMap } from "./layouts";
+import {
+ HyprctlDeviceLayout,
+ HyprctlKeyboard,
+ KbLabelType,
+ LayoutKeys,
+ LayoutValues,
+} from 'lib/types/customModules/kbLayout';
+import { layoutMap } from './layouts';
-export const getKeyboardLayout = (obj: string, format: KbLabelType) => {
- let hyprctlDevices: HyprctlDeviceLayout = JSON.parse(obj);
- let keyboards = hyprctlDevices['keyboards'];
+export const getKeyboardLayout = (obj: string, format: KbLabelType): LayoutKeys | LayoutValues => {
+ const hyprctlDevices: HyprctlDeviceLayout = JSON.parse(obj);
+ const keyboards = hyprctlDevices['keyboards'];
if (keyboards.length === 0) {
- return "No KB!"
+ return format === 'code' ? 'Unknown' : 'Unknown Layout';
}
let mainKb = keyboards.find((kb: HyprctlKeyboard) => kb.main);
@@ -15,7 +21,8 @@ export const getKeyboardLayout = (obj: string, format: KbLabelType) => {
mainKb = keyboards[keyboards.length - 1];
}
- let layout = mainKb['active_keymap'];
+ const layout: LayoutKeys = mainKb['active_keymap'] as LayoutKeys;
+ const foundLayout: LayoutValues = layoutMap[layout];
- return format === "code" ? layoutMap[layout] || layout : layout;
-}
+ return format === 'code' ? foundLayout || layout : layout;
+};
diff --git a/customModules/kblayout/index.ts b/customModules/kblayout/index.ts
index b984141..479bc7e 100644
--- a/customModules/kblayout/index.ts
+++ b/customModules/kblayout/index.ts
@@ -1,49 +1,50 @@
-const hyprland = await Service.import("hyprland");
+const hyprland = await Service.import('hyprland');
-import options from "options";
-import { module } from "../module"
+import options from 'options';
+import { module } from '../module';
-import { inputHandler } from "customModules/utils";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
-import Button from "types/widgets/button";
-import Label from "types/widgets/label";
-import { getKeyboardLayout } from "./getLayout";
+import { inputHandler } from 'customModules/utils';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
+import Button from 'types/widgets/button';
+import Label from 'types/widgets/label';
+import { getKeyboardLayout } from './getLayout';
+import { Module } from 'lib/types/bar';
-const {
- label,
- labelType,
- icon,
- leftClick,
- rightClick,
- middleClick,
- scrollUp,
- scrollDown,
-} = options.bar.customModules.kbLayout;
+const { label, labelType, icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } =
+ options.bar.customModules.kbLayout;
-export const KbInput = () => {
+export const KbInput = (): Module => {
const keyboardModule = module({
- textIcon: icon.bind("value"),
- tooltipText: "",
+ textIcon: icon.bind('value'),
+ tooltipText: '',
labelHook: (self: Label): void => {
- self.hook(hyprland, () => {
- Utils.execAsync('hyprctl devices -j')
- .then((obj) => {
- self.label = getKeyboardLayout(obj, labelType.value);
- })
- .catch((err) => { console.error(err); });
- }, "keyboard-layout");
+ self.hook(
+ hyprland,
+ () => {
+ Utils.execAsync('hyprctl devices -j')
+ .then((obj) => {
+ self.label = getKeyboardLayout(obj, labelType.value);
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+ },
+ 'keyboard-layout',
+ );
self.hook(labelType, () => {
Utils.execAsync('hyprctl devices -j')
.then((obj) => {
self.label = getKeyboardLayout(obj, labelType.value);
})
- .catch((err) => { console.error(err); });
+ .catch((err) => {
+ console.error(err);
+ });
});
},
- boxClass: "kblayout",
- showLabelBinding: label.bind("value"),
+ boxClass: 'kblayout',
+ showLabelBinding: label.bind('value'),
props: {
setup: (self: Button) => {
inputHandler(self, {
@@ -68,6 +69,4 @@ export const KbInput = () => {
});
return keyboardModule;
-}
-
-
+};
diff --git a/customModules/kblayout/layouts.ts b/customModules/kblayout/layouts.ts
index ff4b0e1..ccd37c6 100644
--- a/customModules/kblayout/layouts.ts
+++ b/customModules/kblayout/layouts.ts
@@ -1,584 +1,585 @@
export const layoutMap = {
- "Abkhazian (Russia)": "RU (Ab)",
- "Akan": "GH (Akan)",
- "Albanian": "AL",
- "Albanian (Plisi)": "AL (Plisi)",
- "Albanian (Veqilharxhi)": "AL (Veqilharxhi)",
- "Amharic": "ET",
- "Arabic": "ARA",
- "Arabic (Algeria)": "DZ (Ar)",
- "Arabic (AZERTY, Eastern Arabic numerals)": "ARA (Azerty Digits)",
- "Arabic (AZERTY)": "ARA (Azerty)",
- "Arabic (Buckwalter)": "ARA (Buckwalter)",
- "Arabic (Eastern Arabic numerals)": "ARA (Digits)",
- "Arabic (Macintosh)": "ARA (Mac)",
- "Arabic (Morocco)": "MA",
- "Arabic (OLPC)": "ARA (Olpc)",
- "Arabic (Pakistan)": "PK (Ara)",
- "Arabic (QWERTY, Eastern Arabic numerals)": "ARA (Qwerty Digits)",
- "Arabic (QWERTY)": "ARA (Qwerty)",
- "Arabic (Syria)": "SY",
- "Armenian": "AM",
- "Armenian (alt. eastern)": "AM (Eastern-Alt)",
- "Armenian (alt. phonetic)": "AM (Phonetic-Alt)",
- "Armenian (eastern)": "AM (Eastern)",
- "Armenian (phonetic)": "AM (Phonetic)",
- "Armenian (western)": "AM (Western)",
- "Asturian (Spain, with bottom-dot H and L)": "ES (Ast)",
- "Avatime": "GH (Avn)",
- "Azerbaijani": "AZ",
- "Azerbaijani (Cyrillic)": "AZ (Cyrillic)",
- "Azerbaijani (Iran)": "IR (Azb)",
- "Bambara": "ML",
- "Bangla": "BD",
- "Bangla (India, Baishakhi InScript)": "IN (Ben Inscript)",
- "Bangla (India, Baishakhi)": "IN (Ben Baishakhi)",
- "Bangla (India, Bornona)": "IN (Ben Bornona)",
- "Bangla (India, Gitanjali)": "IN (Ben Gitanjali)",
- "Bangla (India, Probhat)": "IN (Ben Probhat)",
- "Bangla (India)": "IN (Ben)",
- "Bangla (Probhat)": "BD (Probhat)",
- "Bashkirian": "RU (Bak)",
- "Belarusian": "BY",
- "Belarusian (intl.)": "BY (Intl)",
- "Belarusian (Latin)": "BY (Latin)",
- "Belarusian (legacy)": "BY (Legacy)",
- "Belarusian (phonetic)": "BY (Phonetic)",
- "Belgian": "BE",
- "Belgian (alt.)": "BE (Oss)",
- "Belgian (ISO, alt.)": "BE (Iso-Alternate)",
- "Belgian (Latin-9 only, alt.)": "BE (Oss Latin9)",
- "Belgian (no dead keys)": "BE (Nodeadkeys)",
- "Belgian (Wang 724 AZERTY)": "BE (Wang)",
- "Berber (Algeria, Latin)": "DZ",
- "Berber (Algeria, Tifinagh)": "DZ (Ber)",
- "Berber (Morocco, Tifinagh alt.)": "MA (Tifinagh-Alt)",
- "Berber (Morocco, Tifinagh extended phonetic)": "MA (Tifinagh-Extended-Phonetic)",
- "Berber (Morocco, Tifinagh extended)": "MA (Tifinagh-Extended)",
- "Berber (Morocco, Tifinagh phonetic, alt.)": "MA (Tifinagh-Alt-Phonetic)",
- "Berber (Morocco, Tifinagh phonetic)": "MA (Tifinagh-Phonetic)",
- "Berber (Morocco, Tifinagh)": "MA (Tifinagh)",
- "Bosnian": "BA",
- "Bosnian (US, with Bosnian digraphs)": "BA (Unicodeus)",
- "Bosnian (US)": "BA (Us)",
- "Bosnian (with Bosnian digraphs)": "BA (Unicode)",
- "Bosnian (with guillemets)": "BA (Alternatequotes)",
- "Braille": "BRAI",
- "Braille (left-handed inverted thumb)": "BRAI (Left Hand Invert)",
- "Braille (left-handed)": "BRAI (Left Hand)",
- "Braille (right-handed inverted thumb)": "BRAI (Right Hand Invert)",
- "Braille (right-handed)": "BRAI (Right Hand)",
- "Breton (France)": "FR (Bre)",
- "Bulgarian": "BG",
- "Bulgarian (enhanced)": "BG (Bekl)",
- "Bulgarian (new phonetic)": "BG (Bas Phonetic)",
- "Bulgarian (traditional phonetic)": "BG (Phonetic)",
- "Burmese": "MM",
- "Burmese Zawgyi": "MM (Zawgyi)",
- "Cameroon (AZERTY, intl.)": "CM (Azerty)",
- "Cameroon (Dvorak, intl.)": "CM (Dvorak)",
- "Cameroon Multilingual (QWERTY, intl.)": "CM (Qwerty)",
- "Canadian (CSA)": "CA (Multix)",
- "Catalan (Spain, with middle-dot L)": "ES (Cat)",
- "Cherokee": "US (Chr)",
- "Chinese": "CN",
- "Chuvash": "RU (Cv)",
- "Chuvash (Latin)": "RU (Cv Latin)",
- "CloGaelach": "IE (CloGaelach)",
- "Crimean Tatar (Turkish Alt-Q)": "UA (Crh Alt)",
- "Crimean Tatar (Turkish F)": "UA (Crh F)",
- "Crimean Tatar (Turkish Q)": "UA (Crh)",
- "Croatian": "HR",
- "Croatian (US, with Croatian digraphs)": "HR (Unicodeus)",
- "Croatian (US)": "HR (Us)",
- "Croatian (with Croatian digraphs)": "HR (Unicode)",
- "Croatian (with guillemets)": "HR (Alternatequotes)",
- "Czech": "CZ",
- "Czech (QWERTY, extended backslash)": "CZ (Qwerty Bksl)",
- "Czech (QWERTY, Macintosh)": "CZ (Qwerty-Mac)",
- "Czech (QWERTY)": "CZ (Qwerty)",
- "Czech (UCW, only accented letters)": "CZ (Ucw)",
- "Czech (US, Dvorak, UCW support)": "CZ (Dvorak-Ucw)",
- "Czech (with <\\|> key)": "CZ (Bksl)",
- "Danish": "DK",
- "Danish (Dvorak)": "DK (Dvorak)",
- "Danish (Macintosh, no dead keys)": "DK (Mac Nodeadkeys)",
- "Danish (Macintosh)": "DK (Mac)",
- "Danish (no dead keys)": "DK (Nodeadkeys)",
- "Danish (Windows)": "DK (Winkeys)",
- "Dari": "AF",
- "Dari (Afghanistan, OLPC)": "AF (Fa-Olpc)",
- "Dhivehi": "MV",
- "Dutch": "NL",
- "Dutch (Macintosh)": "NL (Mac)",
- "Dutch (standard)": "NL (Std)",
- "Dutch (US)": "NL (Us)",
- "Dzongkha": "BT",
- "English (Australian)": "AU",
- "English (Cameroon)": "CM",
- "English (Canada)": "CA (Eng)",
- "English (classic Dvorak)": "US (Dvorak-Classic)",
- "English (Colemak-DH ISO)": "US (Colemak Dh Iso)",
- "English (Colemak-DH)": "US (Colemak Dh)",
- "English (Colemak)": "US (Colemak)",
- "English (Dvorak, alt. intl.)": "US (Dvorak-Alt-Intl)",
- "English (Dvorak, intl., with dead keys)": "US (Dvorak-Intl)",
- "English (Dvorak, left-handed)": "US (Dvorak-L)",
- "English (Dvorak, Macintosh)": "US (Dvorak-Mac)",
- "English (Dvorak, right-handed)": "US (Dvorak-R)",
- "English (Dvorak)": "US (Dvorak)",
- "English (Ghana, GILLBT)": "GH (Gillbt)",
- "English (Ghana, multilingual)": "GH (Generic)",
- "English (Ghana)": "GH",
- "English (India, with rupee)": "IN (Eng)",
- "English (intl., with AltGr dead keys)": "US (Altgr-Intl)",
- "English (Macintosh)": "US (Mac)",
- "English (Mali, US, intl.)": "ML (Us-Intl)",
- "English (Mali, US, Macintosh)": "ML (Us-Mac)",
- "English (Nigeria)": "NG",
- "English (Norman)": "US (Norman)",
- "English (programmer Dvorak)": "US (Dvp)",
- "English (South Africa)": "ZA",
- "English (the divide/multiply toggle the layout)": "US (Olpc2)",
- "English (UK, Colemak-DH)": "GB (Colemak Dh)",
- "English (UK, Colemak)": "GB (Colemak)",
- "English (UK, Dvorak, with UK punctuation)": "GB (Dvorakukp)",
- "English (UK, Dvorak)": "GB (Dvorak)",
- "English (UK, extended, Windows)": "GB (Extd)",
- "English (UK, intl., with dead keys)": "GB (Intl)",
- "English (UK, Macintosh, intl.)": "GB (Mac Intl)",
- "English (UK, Macintosh)": "GB (Mac)",
- "English (UK)": "GB",
- "English (US, alt. intl.)": "US (Alt-Intl)",
- "English (US, euro on 5)": "US (Euro)",
- "English (US, intl., with dead keys)": "US (Intl)",
- "English (US, Symbolic)": "US (Symbolic)",
- "English (US)": "US",
- "English (Workman, intl., with dead keys)": "US (Workman-Intl)",
- "English (Workman)": "US (Workman)",
- "Esperanto": "EPO",
- "Esperanto (Brazil, Nativo)": "BR (Nativo-Epo)",
- "Esperanto (legacy)": "EPO (Legacy)",
- "Esperanto (Portugal, Nativo)": "PT (Nativo-Epo)",
- "Estonian": "EE",
- "Estonian (Dvorak)": "EE (Dvorak)",
- "Estonian (no dead keys)": "EE (Nodeadkeys)",
- "Estonian (US)": "EE (Us)",
- "Ewe": "GH (Ewe)",
- "Faroese": "FO",
- "Faroese (no dead keys)": "FO (Nodeadkeys)",
- "Filipino": "PH",
- "Filipino (Capewell-Dvorak, Baybayin)": "PH (Capewell-Dvorak-Bay)",
- "Filipino (Capewell-Dvorak, Latin)": "PH (Capewell-Dvorak)",
- "Filipino (Capewell-QWERF 2006, Baybayin)": "PH (Capewell-Qwerf2k6-Bay)",
- "Filipino (Capewell-QWERF 2006, Latin)": "PH (Capewell-Qwerf2k6)",
- "Filipino (Colemak, Baybayin)": "PH (Colemak-Bay)",
- "Filipino (Colemak, Latin)": "PH (Colemak)",
- "Filipino (Dvorak, Baybayin)": "PH (Dvorak-Bay)",
- "Filipino (Dvorak, Latin)": "PH (Dvorak)",
- "Filipino (QWERTY, Baybayin)": "PH (Qwerty-Bay)",
- "Finnish": "FI",
- "Finnish (classic, no dead keys)": "FI (Nodeadkeys)",
- "Finnish (classic)": "FI (Classic)",
- "Finnish (Macintosh)": "FI (Mac)",
- "Finnish (Windows)": "FI (Winkeys)",
- "French": "FR",
- "French (alt., Latin-9 only)": "FR (Oss Latin9)",
- "French (alt., no dead keys)": "FR (Oss Nodeadkeys)",
- "French (alt.)": "FR (Oss)",
- "French (AZERTY, AFNOR)": "FR (Afnor)",
- "French (AZERTY)": "FR (Azerty)",
- "French (BEPO, AFNOR)": "FR (Bepo Afnor)",
- "French (BEPO, Latin-9 only)": "FR (Bepo Latin9)",
- "French (BEPO)": "FR (Bepo)",
- "French (Cameroon)": "CM (French)",
- "French (Canada, Dvorak)": "CA (Fr-Dvorak)",
- "French (Canada, legacy)": "CA (Fr-Legacy)",
- "French (Canada)": "CA",
- "French (Democratic Republic of the Congo)": "CD",
- "French (Dvorak)": "FR (Dvorak)",
- "French (legacy, alt., no dead keys)": "FR (Latin9 Nodeadkeys)",
- "French (legacy, alt.)": "FR (Latin9)",
- "French (Macintosh)": "FR (Mac)",
- "French (Mali, alt.)": "ML (Fr-Oss)",
- "French (Morocco)": "MA (French)",
- "French (no dead keys)": "FR (Nodeadkeys)",
- "French (Switzerland, Macintosh)": "CH (Fr Mac)",
- "French (Switzerland, no dead keys)": "CH (Fr Nodeadkeys)",
- "French (Switzerland)": "CH (Fr)",
- "French (Togo)": "TG",
- "French (US)": "FR (Us)",
- "Friulian (Italy)": "IT (Fur)",
- "Fula": "GH (Fula)",
- "Ga": "GH (Ga)",
- "Georgian": "GE",
- "Georgian (ergonomic)": "GE (Ergonomic)",
- "Georgian (France, AZERTY Tskapo)": "FR (Geo)",
- "Georgian (Italy)": "IT (Geo)",
- "Georgian (MESS)": "GE (Mess)",
- "German": "DE",
- "German (Austria, Macintosh)": "AT (Mac)",
- "German (Austria, no dead keys)": "AT (Nodeadkeys)",
- "German (Austria)": "AT",
- "German (dead acute)": "DE (Deadacute)",
- "German (dead grave acute)": "DE (Deadgraveacute)",
- "German (dead tilde)": "DE (Deadtilde)",
- "German (Dvorak)": "DE (Dvorak)",
- "German (E1)": "DE (E1)",
- "German (E2)": "DE (E2)",
- "German (Macintosh, no dead keys)": "DE (Mac Nodeadkeys)",
- "German (Macintosh)": "DE (Mac)",
- "German (Neo 2)": "DE (Neo)",
- "German (no dead keys)": "DE (Nodeadkeys)",
- "German (QWERTY)": "DE (Qwerty)",
- "German (Switzerland, legacy)": "CH (Legacy)",
- "German (Switzerland, Macintosh)": "CH (De Mac)",
- "German (Switzerland, no dead keys)": "CH (De Nodeadkeys)",
- "German (Switzerland)": "CH",
- "German (T3)": "DE (T3)",
- "German (US)": "DE (Us)",
- "Greek": "GR",
- "Greek (extended)": "GR (Extended)",
- "Greek (no dead keys)": "GR (Nodeadkeys)",
- "Greek (polytonic)": "GR (Polytonic)",
- "Greek (simple)": "GR (Simple)",
- "Gujarati": "IN (Guj)",
- "Hanyu Pinyin Letters (with AltGr dead keys)": "CN (Altgr-Pinyin)",
- "Hausa (Ghana)": "GH (Hausa)",
- "Hausa (Nigeria)": "NG (Hausa)",
- "Hawaiian": "US (Haw)",
- "Hebrew": "IL",
- "Hebrew (Biblical, Tiro)": "IL (Biblical)",
- "Hebrew (lyx)": "IL (Lyx)",
- "Hebrew (phonetic)": "IL (Phonetic)",
- "Hindi (Bolnagri)": "IN (Bolnagri)",
- "Hindi (KaGaPa, phonetic)": "IN (Hin-Kagapa)",
- "Hindi (Wx)": "IN (Hin-Wx)",
- "Hungarian": "HU",
- "Hungarian (no dead keys)": "HU (Nodeadkeys)",
- "Hungarian (QWERTY, 101-key, comma, dead keys)": "HU (101 Qwerty Comma Dead)",
- "Hungarian (QWERTY, 101-key, comma, no dead keys)": "HU (101 Qwerty Comma Nodead)",
- "Hungarian (QWERTY, 101-key, dot, dead keys)": "HU (101 Qwerty Dot Dead)",
- "Hungarian (QWERTY, 101-key, dot, no dead keys)": "HU (101 Qwerty Dot Nodead)",
- "Hungarian (QWERTY, 102-key, comma, dead keys)": "HU (102 Qwerty Comma Dead)",
- "Hungarian (QWERTY, 102-key, comma, no dead keys)": "HU (102 Qwerty Comma Nodead)",
- "Hungarian (QWERTY, 102-key, dot, dead keys)": "HU (102 Qwerty Dot Dead)",
- "Hungarian (QWERTY, 102-key, dot, no dead keys)": "HU (102 Qwerty Dot Nodead)",
- "Hungarian (QWERTY)": "HU (Qwerty)",
- "Hungarian (QWERTZ, 101-key, comma, dead keys)": "HU (101 Qwertz Comma Dead)",
- "Hungarian (QWERTZ, 101-key, comma, no dead keys)": "HU (101 Qwertz Comma Nodead)",
- "Hungarian (QWERTZ, 101-key, dot, dead keys)": "HU (101 Qwertz Dot Dead)",
- "Hungarian (QWERTZ, 101-key, dot, no dead keys)": "HU (101 Qwertz Dot Nodead)",
- "Hungarian (QWERTZ, 102-key, comma, dead keys)": "HU (102 Qwertz Comma Dead)",
- "Hungarian (QWERTZ, 102-key, comma, no dead keys)": "HU (102 Qwertz Comma Nodead)",
- "Hungarian (QWERTZ, 102-key, dot, dead keys)": "HU (102 Qwertz Dot Dead)",
- "Hungarian (QWERTZ, 102-key, dot, no dead keys)": "HU (102 Qwertz Dot Nodead)",
- "Hungarian (standard)": "HU (Standard)",
- "Icelandic": "IS",
- "Icelandic (Dvorak)": "IS (Dvorak)",
- "Icelandic (Macintosh, legacy)": "IS (Mac Legacy)",
- "Icelandic (Macintosh)": "IS (Mac)",
- "Igbo": "NG (Igbo)",
- "Indian": "IN",
- "Indic IPA": "IN (Iipa)",
- "Indonesian (Arab Melayu, extended phonetic)": "ID (Melayu-Phoneticx)",
- "Indonesian (Arab Melayu, phonetic)": "ID (Melayu-Phonetic)",
- "Indonesian (Arab Pegon, phonetic)": "ID (Pegon-Phonetic)",
- "Indonesian (Latin)": "ID",
- "Inuktitut": "CA (Ike)",
- "Iraqi": "IQ",
- "Irish": "IE",
- "Irish (UnicodeExpert)": "IE (UnicodeExpert)",
- "Italian": "IT",
- "Italian (IBM 142)": "IT (Ibm)",
- "Italian (intl., with dead keys)": "IT (Intl)",
- "Italian (Macintosh)": "IT (Mac)",
- "Italian (no dead keys)": "IT (Nodeadkeys)",
- "Italian (US)": "IT (Us)",
- "Italian (Windows)": "IT (Winkeys)",
- "Japanese": "JP",
- "Japanese (Dvorak)": "JP (Dvorak)",
- "Japanese (Kana 86)": "JP (Kana86)",
- "Japanese (Kana)": "JP (Kana)",
- "Japanese (Macintosh)": "JP (Mac)",
- "Japanese (OADG 109A)": "JP (OADG109A)",
- "Javanese": "ID (Javanese)",
- "Kabyle (AZERTY, with dead keys)": "DZ (Azerty-Deadkeys)",
- "Kabyle (QWERTY, UK, with dead keys)": "DZ (Qwerty-Gb-Deadkeys)",
- "Kabyle (QWERTY, US, with dead keys)": "DZ (Qwerty-Us-Deadkeys)",
- "Kalmyk": "RU (Xal)",
- "Kannada": "IN (Kan)",
- "Kannada (KaGaPa, phonetic)": "IN (Kan-Kagapa)",
- "Kashubian": "PL (Csb)",
- "Kazakh": "KZ",
- "Kazakh (extended)": "KZ (Ext)",
- "Kazakh (Latin)": "KZ (Latin)",
- "Kazakh (with Russian)": "KZ (Kazrus)",
- "Khmer (Cambodia)": "KH",
- "Kikuyu": "KE (Kik)",
- "Komi": "RU (Kom)",
- "Korean": "KR",
- "Korean (101/104-key compatible)": "KR (Kr104)",
- "Kurdish (Iran, Arabic-Latin)": "IR (Ku Ara)",
- "Kurdish (Iran, F)": "IR (Ku F)",
- "Kurdish (Iran, Latin Alt-Q)": "IR (Ku Alt)",
- "Kurdish (Iran, Latin Q)": "IR (Ku)",
- "Kurdish (Iraq, Arabic-Latin)": "IQ (Ku Ara)",
- "Kurdish (Iraq, F)": "IQ (Ku F)",
- "Kurdish (Iraq, Latin Alt-Q)": "IQ (Ku Alt)",
- "Kurdish (Iraq, Latin Q)": "IQ (Ku)",
- "Kurdish (Syria, F)": "SY (Ku F)",
- "Kurdish (Syria, Latin Alt-Q)": "SY (Ku Alt)",
- "Kurdish (Syria, Latin Q)": "SY (Ku)",
- "Kurdish (Turkey, F)": "TR (Ku F)",
- "Kurdish (Turkey, Latin Alt-Q)": "TR (Ku Alt)",
- "Kurdish (Turkey, Latin Q)": "TR (Ku)",
- "Kyrgyz": "KG",
- "Kyrgyz (phonetic)": "KG (Phonetic)",
- "Lao": "LA",
- "Lao (STEA)": "LA (Stea)",
- "Latvian": "LV",
- "Latvian (adapted)": "LV (Adapted)",
- "Latvian (apostrophe)": "LV (Apostrophe)",
- "Latvian (ergonomic, ŪGJRMV)": "LV (Ergonomic)",
- "Latvian (F)": "LV (Fkey)",
- "Latvian (modern)": "LV (Modern)",
- "Latvian (tilde)": "LV (Tilde)",
- "Lithuanian": "LT",
- "Lithuanian (IBM LST 1205-92)": "LT (Ibm)",
- "Lithuanian (LEKP)": "LT (Lekp)",
- "Lithuanian (LEKPa)": "LT (Lekpa)",
- "Lithuanian (Ratise)": "LT (Ratise)",
- "Lithuanian (standard)": "LT (Std)",
- "Lithuanian (US)": "LT (Us)",
- "Lower Sorbian": "DE (Dsb)",
- "Lower Sorbian (QWERTZ)": "DE (Dsb Qwertz)",
- "Macedonian": "MK",
- "Macedonian (no dead keys)": "MK (Nodeadkeys)",
- "Malay (Jawi, Arabic Keyboard)": "MY",
- "Malay (Jawi, phonetic)": "MY (Phonetic)",
- "Malayalam": "IN (Mal)",
- "Malayalam (enhanced InScript, with rupee)": "IN (Mal Enhanced)",
- "Malayalam (Lalitha)": "IN (Mal Lalitha)",
- "Maltese": "MT",
- "Maltese (UK, with AltGr overrides)": "MT (Alt-Gb)",
- "Maltese (US, with AltGr overrides)": "MT (Alt-Us)",
- "Maltese (US)": "MT (Us)",
- "Manipuri (Eeyek)": "IN (Eeyek)",
- "Maori": "MAO",
- "Marathi (enhanced InScript)": "IN (Marathi)",
- "Marathi (KaGaPa, phonetic)": "IN (Mar-Kagapa)",
- "Mari": "RU (Chm)",
- "Mmuock": "CM (Mmuock)",
- "Moldavian": "MD",
- "Moldavian (Gagauz)": "MD (Gag)",
- "Mon": "MM (Mnw)",
- "Mon (A1)": "MM (Mnw-A1)",
- "Mongolian": "MN",
- "Mongolian (Bichig)": "CN (Mon Trad)",
- "Mongolian (Galik)": "CN (Mon Trad Galik)",
- "Mongolian (Manchu Galik)": "CN (Mon Manchu Galik)",
- "Mongolian (Manchu)": "CN (Mon Trad Manchu)",
- "Mongolian (Todo Galik)": "CN (Mon Todo Galik)",
- "Mongolian (Todo)": "CN (Mon Trad Todo)",
- "Mongolian (Xibe)": "CN (Mon Trad Xibe)",
- "Montenegrin": "ME",
- "Montenegrin (Cyrillic, with guillemets)": "ME (Cyrillicalternatequotes)",
- "Montenegrin (Cyrillic, ZE and ZHE swapped)": "ME (Cyrillicyz)",
- "Montenegrin (Cyrillic)": "ME (Cyrillic)",
- "Montenegrin (Latin, QWERTY)": "ME (Latinyz)",
- "Montenegrin (Latin, Unicode, QWERTY)": "ME (Latinunicodeyz)",
- "Montenegrin (Latin, Unicode)": "ME (Latinunicode)",
- "Montenegrin (Latin, with guillemets)": "ME (Latinalternatequotes)",
- "N'Ko (AZERTY)": "GN",
- "Nepali": "NP",
- "Northern Saami (Finland)": "FI (Smi)",
- "Northern Saami (Norway, no dead keys)": "NO (Smi Nodeadkeys)",
- "Northern Saami (Norway)": "NO (Smi)",
- "Northern Saami (Sweden)": "SE (Smi)",
- "Norwegian": "NO",
- "Norwegian (Colemak)": "NO (Colemak)",
- "Norwegian (Dvorak)": "NO (Dvorak)",
- "Norwegian (Macintosh, no dead keys)": "NO (Mac Nodeadkeys)",
- "Norwegian (Macintosh)": "NO (Mac)",
- "Norwegian (no dead keys)": "NO (Nodeadkeys)",
- "Norwegian (Windows)": "NO (Winkeys)",
- "Occitan": "FR (Oci)",
- "Ogham": "IE (Ogam)",
- "Ogham (IS434)": "IE (Ogam Is434)",
- "Ol Chiki": "IN (Olck)",
- "Old Turkic": "TR (Otk)",
- "Old Turkic (F)": "TR (Otkf)",
- "Oriya": "IN (Ori)",
- "Oriya (Bolnagri)": "IN (Ori-Bolnagri)",
- "Oriya (Wx)": "IN (Ori-Wx)",
- "Ossetian (Georgia)": "GE (Os)",
- "Ossetian (legacy)": "RU (Os Legacy)",
- "Ossetian (Windows)": "RU (Os Winkeys)",
- "Ottoman (F)": "TR (Otf)",
- "Ottoman (Q)": "TR (Ot)",
- "Pannonian Rusyn": "RS (Rue)",
- "Pashto": "AF (Ps)",
- "Pashto (Afghanistan, OLPC)": "AF (Ps-Olpc)",
- "Persian": "IR",
- "Persian (with Persian keypad)": "IR (Pes Keypad)",
- "Polish": "PL",
- "Polish (British keyboard)": "GB (Pl)",
- "Polish (Dvorak, with Polish quotes on key 1)": "PL (Dvorak Altquotes)",
- "Polish (Dvorak, with Polish quotes on quotemark key)": "PL (Dvorak Quotes)",
- "Polish (Dvorak)": "PL (Dvorak)",
- "Polish (legacy)": "PL (Legacy)",
- "Polish (programmer Dvorak)": "PL (Dvp)",
- "Polish (QWERTZ)": "PL (Qwertz)",
- "Portuguese": "PT",
- "Portuguese (Brazil, Dvorak)": "BR (Dvorak)",
- "Portuguese (Brazil, IBM/Lenovo ThinkPad)": "BR (Thinkpad)",
- "Portuguese (Brazil, Nativo for US keyboards)": "BR (Nativo-Us)",
- "Portuguese (Brazil, Nativo)": "BR (Nativo)",
- "Portuguese (Brazil, no dead keys)": "BR (Nodeadkeys)",
- "Portuguese (Brazil)": "BR",
- "Portuguese (Macintosh, no dead keys)": "PT (Mac Nodeadkeys)",
- "Portuguese (Macintosh)": "PT (Mac)",
- "Portuguese (Nativo for US keyboards)": "PT (Nativo-Us)",
- "Portuguese (Nativo)": "PT (Nativo)",
- "Portuguese (no dead keys)": "PT (Nodeadkeys)",
- "Punjabi (Gurmukhi Jhelum)": "IN (Jhelum)",
- "Punjabi (Gurmukhi)": "IN (Guru)",
- "Romanian": "RO",
- "Romanian (Germany, no dead keys)": "DE (Ro Nodeadkeys)",
- "Romanian (Germany)": "DE (Ro)",
- "Romanian (standard)": "RO (Std)",
- "Romanian (Windows)": "RO (Winkeys)",
- "Russian": "RU",
- "Russian (Belarus)": "BY (Ru)",
- "Russian (Czech, phonetic)": "CZ (Rus)",
- "Russian (DOS)": "RU (Dos)",
- "Russian (engineering, EN)": "RU (Ruchey En)",
- "Russian (engineering, RU)": "RU (Ruchey Ru)",
- "Russian (Georgia)": "GE (Ru)",
- "Russian (Germany, phonetic)": "DE (Ru)",
- "Russian (Kazakhstan, with Kazakh)": "KZ (Ruskaz)",
- "Russian (legacy)": "RU (Legacy)",
- "Russian (Macintosh)": "RU (Mac)",
- "Russian (phonetic, AZERTY)": "RU (Phonetic Azerty)",
- "Russian (phonetic, Dvorak)": "RU (Phonetic Dvorak)",
- "Russian (phonetic, French)": "RU (Phonetic Fr)",
- "Russian (phonetic, Windows)": "RU (Phonetic Winkeys)",
- "Russian (phonetic, YAZHERTY)": "RU (Phonetic YAZHERTY)",
- "Russian (phonetic)": "RU (Phonetic)",
- "Russian (Poland, phonetic Dvorak)": "PL (Ru Phonetic Dvorak)",
- "Russian (Sweden, phonetic, no dead keys)": "SE (Rus Nodeadkeys)",
- "Russian (Sweden, phonetic)": "SE (Rus)",
- "Russian (typewriter, legacy)": "RU (Typewriter-Legacy)",
- "Russian (typewriter)": "RU (Typewriter)",
- "Russian (Ukraine, standard RSTU)": "UA (Rstu Ru)",
- "Russian (US, phonetic)": "US (Rus)",
- "Saisiyat (Taiwan)": "TW (Saisiyat)",
- "Samogitian": "LT (Sgs)",
- "Sanskrit (KaGaPa, phonetic)": "IN (San-Kagapa)",
- "Scottish Gaelic": "GB (Gla)",
- "Serbian": "RS",
- "Serbian (Cyrillic, with guillemets)": "RS (Alternatequotes)",
- "Serbian (Cyrillic, ZE and ZHE swapped)": "RS (Yz)",
- "Serbian (Latin, QWERTY)": "RS (Latinyz)",
- "Serbian (Latin, Unicode, QWERTY)": "RS (Latinunicodeyz)",
- "Serbian (Latin, Unicode)": "RS (Latinunicode)",
- "Serbian (Latin, with guillemets)": "RS (Latinalternatequotes)",
- "Serbian (Latin)": "RS (Latin)",
- "Serbian (Russia)": "RU (Srp)",
- "Serbo-Croatian (US)": "US (Hbs)",
- "Shan": "MM (Shn)",
- "Shan (Zawgyi Tai)": "MM (Zgt)",
- "Sicilian": "IT (Scn)",
- "Silesian": "PL (Szl)",
- "Sindhi": "PK (Snd)",
- "Sinhala (phonetic)": "LK",
- "Sinhala (US)": "LK (Us)",
- "Slovak": "SK",
- "Slovak (extended backslash)": "SK (Bksl)",
- "Slovak (QWERTY, extended backslash)": "SK (Qwerty Bksl)",
- "Slovak (QWERTY)": "SK (Qwerty)",
- "Slovenian": "SI",
- "Slovenian (US)": "SI (Us)",
- "Slovenian (with guillemets)": "SI (Alternatequotes)",
- "Spanish": "ES",
- "Spanish (dead tilde)": "ES (Deadtilde)",
- "Spanish (Dvorak)": "ES (Dvorak)",
- "Spanish (Latin American, Colemak)": "LATAM (Colemak)",
- "Spanish (Latin American, dead tilde)": "LATAM (Deadtilde)",
- "Spanish (Latin American, Dvorak)": "LATAM (Dvorak)",
- "Spanish (Latin American, no dead keys)": "LATAM (Nodeadkeys)",
- "Spanish (Latin American)": "LATAM",
- "Spanish (Macintosh)": "ES (Mac)",
- "Spanish (no dead keys)": "ES (Nodeadkeys)",
- "Spanish (Windows)": "ES (Winkeys)",
- "Swahili (Kenya)": "KE",
- "Swahili (Tanzania)": "TZ",
- "Swedish": "SE",
- "Swedish (Dvorak, intl.)": "SE (Us Dvorak)",
- "Swedish (Dvorak)": "SE (Dvorak)",
- "Swedish (Macintosh)": "SE (Mac)",
- "Swedish (no dead keys)": "SE (Nodeadkeys)",
- "Swedish (Svdvorak)": "SE (Svdvorak)",
- "Swedish (US)": "SE (Us)",
- "Swedish Sign Language": "SE (Swl)",
- "Syriac": "SY (Syc)",
- "Syriac (phonetic)": "SY (Syc Phonetic)",
- "Taiwanese": "TW",
- "Taiwanese (indigenous)": "TW (Indigenous)",
- "Tajik": "TJ",
- "Tajik (legacy)": "TJ (Legacy)",
- "Tamil (InScript, with Arabic numerals)": "IN (Tam)",
- "Tamil (InScript, with Tamil numerals)": "IN (Tam Tamilnumbers)",
- "Tamil (Sri Lanka, TamilNet '99, TAB encoding)": "LK (Tam TAB)",
- "Tamil (Sri Lanka, TamilNet '99)": "LK (Tam Unicode)",
- "Tamil (TamilNet '99 with Tamil numerals)": "IN (Tamilnet Tamilnumbers)",
- "Tamil (TamilNet '99, TAB encoding)": "IN (Tamilnet TAB)",
- "Tamil (TamilNet '99, TSCII encoding)": "IN (Tamilnet TSCII)",
- "Tamil (TamilNet '99)": "IN (Tamilnet)",
- "Tarifit": "MA (Rif)",
- "Tatar": "RU (Tt)",
- "Telugu": "IN (Tel)",
- "Telugu (KaGaPa, phonetic)": "IN (Tel-Kagapa)",
- "Telugu (Sarala)": "IN (Tel-Sarala)",
- "Thai": "TH",
- "Thai (Pattachote)": "TH (Pat)",
- "Thai (TIS-820.2538)": "TH (Tis)",
- "Tibetan": "CN (Tib)",
- "Tibetan (with ASCII numerals)": "CN (Tib Asciinum)",
- "Tswana": "BW",
- "Turkish": "TR",
- "Turkish (Alt-Q)": "TR (Alt)",
- "Turkish (E)": "TR (E)",
- "Turkish (F)": "TR (F)",
- "Turkish (Germany)": "DE (Tr)",
- "Turkish (intl., with dead keys)": "TR (Intl)",
- "Turkmen": "TM",
- "Turkmen (Alt-Q)": "TM (Alt)",
- "Udmurt": "RU (Udm)",
- "Ukrainian": "UA",
- "Ukrainian (homophonic)": "UA (Homophonic)",
- "Ukrainian (legacy)": "UA (Legacy)",
- "Ukrainian (macOS)": "UA (MacOS)",
- "Ukrainian (phonetic)": "UA (Phonetic)",
- "Ukrainian (standard RSTU)": "UA (Rstu)",
- "Ukrainian (typewriter)": "UA (Typewriter)",
- "Ukrainian (Windows)": "UA (Winkeys)",
- "Urdu (alt. phonetic)": "IN (Urd-Phonetic3)",
- "Urdu (Pakistan, CRULP)": "PK (Urd-Crulp)",
- "Urdu (Pakistan, NLA)": "PK (Urd-Nla)",
- "Urdu (Pakistan)": "PK",
- "Urdu (phonetic)": "IN (Urd-Phonetic)",
- "Urdu (Windows)": "IN (Urd-Winkeys)",
- "Uyghur": "CN (Ug)",
- "Uzbek": "UZ",
- "Uzbek (Afghanistan, OLPC)": "AF (Uz-Olpc)",
- "Uzbek (Afghanistan)": "AF (Uz)",
- "Uzbek (Latin)": "UZ (Latin)",
- "Vietnamese": "VN",
- "Vietnamese (France)": "VN (Fr)",
- "Vietnamese (US)": "VN (Us)",
- "Wolof": "SN",
- "Yakut": "RU (Sah)",
- "Yoruba": "NG (Yoruba)"
-};
+ 'Abkhazian (Russia)': 'RU (Ab)',
+ Akan: 'GH (Akan)',
+ Albanian: 'AL',
+ 'Albanian (Plisi)': 'AL (Plisi)',
+ 'Albanian (Veqilharxhi)': 'AL (Veqilharxhi)',
+ Amharic: 'ET',
+ Arabic: 'ARA',
+ 'Arabic (Algeria)': 'DZ (Ar)',
+ 'Arabic (AZERTY, Eastern Arabic numerals)': 'ARA (Azerty Digits)',
+ 'Arabic (AZERTY)': 'ARA (Azerty)',
+ 'Arabic (Buckwalter)': 'ARA (Buckwalter)',
+ 'Arabic (Eastern Arabic numerals)': 'ARA (Digits)',
+ 'Arabic (Macintosh)': 'ARA (Mac)',
+ 'Arabic (Morocco)': 'MA',
+ 'Arabic (OLPC)': 'ARA (Olpc)',
+ 'Arabic (Pakistan)': 'PK (Ara)',
+ 'Arabic (QWERTY, Eastern Arabic numerals)': 'ARA (Qwerty Digits)',
+ 'Arabic (QWERTY)': 'ARA (Qwerty)',
+ 'Arabic (Syria)': 'SY',
+ Armenian: 'AM',
+ 'Armenian (alt. eastern)': 'AM (Eastern-Alt)',
+ 'Armenian (alt. phonetic)': 'AM (Phonetic-Alt)',
+ 'Armenian (eastern)': 'AM (Eastern)',
+ 'Armenian (phonetic)': 'AM (Phonetic)',
+ 'Armenian (western)': 'AM (Western)',
+ 'Asturian (Spain, with bottom-dot H and L)': 'ES (Ast)',
+ Avatime: 'GH (Avn)',
+ Azerbaijani: 'AZ',
+ 'Azerbaijani (Cyrillic)': 'AZ (Cyrillic)',
+ 'Azerbaijani (Iran)': 'IR (Azb)',
+ Bambara: 'ML',
+ Bangla: 'BD',
+ 'Bangla (India, Baishakhi InScript)': 'IN (Ben Inscript)',
+ 'Bangla (India, Baishakhi)': 'IN (Ben Baishakhi)',
+ 'Bangla (India, Bornona)': 'IN (Ben Bornona)',
+ 'Bangla (India, Gitanjali)': 'IN (Ben Gitanjali)',
+ 'Bangla (India, Probhat)': 'IN (Ben Probhat)',
+ 'Bangla (India)': 'IN (Ben)',
+ 'Bangla (Probhat)': 'BD (Probhat)',
+ Bashkirian: 'RU (Bak)',
+ Belarusian: 'BY',
+ 'Belarusian (intl.)': 'BY (Intl)',
+ 'Belarusian (Latin)': 'BY (Latin)',
+ 'Belarusian (legacy)': 'BY (Legacy)',
+ 'Belarusian (phonetic)': 'BY (Phonetic)',
+ Belgian: 'BE',
+ 'Belgian (alt.)': 'BE (Oss)',
+ 'Belgian (ISO, alt.)': 'BE (Iso-Alternate)',
+ 'Belgian (Latin-9 only, alt.)': 'BE (Oss Latin9)',
+ 'Belgian (no dead keys)': 'BE (Nodeadkeys)',
+ 'Belgian (Wang 724 AZERTY)': 'BE (Wang)',
+ 'Berber (Algeria, Latin)': 'DZ',
+ 'Berber (Algeria, Tifinagh)': 'DZ (Ber)',
+ 'Berber (Morocco, Tifinagh alt.)': 'MA (Tifinagh-Alt)',
+ 'Berber (Morocco, Tifinagh extended phonetic)': 'MA (Tifinagh-Extended-Phonetic)',
+ 'Berber (Morocco, Tifinagh extended)': 'MA (Tifinagh-Extended)',
+ 'Berber (Morocco, Tifinagh phonetic, alt.)': 'MA (Tifinagh-Alt-Phonetic)',
+ 'Berber (Morocco, Tifinagh phonetic)': 'MA (Tifinagh-Phonetic)',
+ 'Berber (Morocco, Tifinagh)': 'MA (Tifinagh)',
+ Bosnian: 'BA',
+ 'Bosnian (US, with Bosnian digraphs)': 'BA (Unicodeus)',
+ 'Bosnian (US)': 'BA (Us)',
+ 'Bosnian (with Bosnian digraphs)': 'BA (Unicode)',
+ 'Bosnian (with guillemets)': 'BA (Alternatequotes)',
+ Braille: 'BRAI',
+ 'Braille (left-handed inverted thumb)': 'BRAI (Left Hand Invert)',
+ 'Braille (left-handed)': 'BRAI (Left Hand)',
+ 'Braille (right-handed inverted thumb)': 'BRAI (Right Hand Invert)',
+ 'Braille (right-handed)': 'BRAI (Right Hand)',
+ 'Breton (France)': 'FR (Bre)',
+ Bulgarian: 'BG',
+ 'Bulgarian (enhanced)': 'BG (Bekl)',
+ 'Bulgarian (new phonetic)': 'BG (Bas Phonetic)',
+ 'Bulgarian (traditional phonetic)': 'BG (Phonetic)',
+ Burmese: 'MM',
+ 'Burmese Zawgyi': 'MM (Zawgyi)',
+ 'Cameroon (AZERTY, intl.)': 'CM (Azerty)',
+ 'Cameroon (Dvorak, intl.)': 'CM (Dvorak)',
+ 'Cameroon Multilingual (QWERTY, intl.)': 'CM (Qwerty)',
+ 'Canadian (CSA)': 'CA (Multix)',
+ 'Catalan (Spain, with middle-dot L)': 'ES (Cat)',
+ Cherokee: 'US (Chr)',
+ Chinese: 'CN',
+ Chuvash: 'RU (Cv)',
+ 'Chuvash (Latin)': 'RU (Cv Latin)',
+ CloGaelach: 'IE (CloGaelach)',
+ 'Crimean Tatar (Turkish Alt-Q)': 'UA (Crh Alt)',
+ 'Crimean Tatar (Turkish F)': 'UA (Crh F)',
+ 'Crimean Tatar (Turkish Q)': 'UA (Crh)',
+ Croatian: 'HR',
+ 'Croatian (US, with Croatian digraphs)': 'HR (Unicodeus)',
+ 'Croatian (US)': 'HR (Us)',
+ 'Croatian (with Croatian digraphs)': 'HR (Unicode)',
+ 'Croatian (with guillemets)': 'HR (Alternatequotes)',
+ Czech: 'CZ',
+ 'Czech (QWERTY, extended backslash)': 'CZ (Qwerty Bksl)',
+ 'Czech (QWERTY, Macintosh)': 'CZ (Qwerty-Mac)',
+ 'Czech (QWERTY)': 'CZ (Qwerty)',
+ 'Czech (UCW, only accented letters)': 'CZ (Ucw)',
+ 'Czech (US, Dvorak, UCW support)': 'CZ (Dvorak-Ucw)',
+ 'Czech (with <\\|> key)': 'CZ (Bksl)',
+ Danish: 'DK',
+ 'Danish (Dvorak)': 'DK (Dvorak)',
+ 'Danish (Macintosh, no dead keys)': 'DK (Mac Nodeadkeys)',
+ 'Danish (Macintosh)': 'DK (Mac)',
+ 'Danish (no dead keys)': 'DK (Nodeadkeys)',
+ 'Danish (Windows)': 'DK (Winkeys)',
+ Dari: 'AF',
+ 'Dari (Afghanistan, OLPC)': 'AF (Fa-Olpc)',
+ Dhivehi: 'MV',
+ Dutch: 'NL',
+ 'Dutch (Macintosh)': 'NL (Mac)',
+ 'Dutch (standard)': 'NL (Std)',
+ 'Dutch (US)': 'NL (Us)',
+ Dzongkha: 'BT',
+ 'English (Australian)': 'AU',
+ 'English (Cameroon)': 'CM',
+ 'English (Canada)': 'CA (Eng)',
+ 'English (classic Dvorak)': 'US (Dvorak-Classic)',
+ 'English (Colemak-DH ISO)': 'US (Colemak Dh Iso)',
+ 'English (Colemak-DH)': 'US (Colemak Dh)',
+ 'English (Colemak)': 'US (Colemak)',
+ 'English (Dvorak, alt. intl.)': 'US (Dvorak-Alt-Intl)',
+ 'English (Dvorak, intl., with dead keys)': 'US (Dvorak-Intl)',
+ 'English (Dvorak, left-handed)': 'US (Dvorak-L)',
+ 'English (Dvorak, Macintosh)': 'US (Dvorak-Mac)',
+ 'English (Dvorak, right-handed)': 'US (Dvorak-R)',
+ 'English (Dvorak)': 'US (Dvorak)',
+ 'English (Ghana, GILLBT)': 'GH (Gillbt)',
+ 'English (Ghana, multilingual)': 'GH (Generic)',
+ 'English (Ghana)': 'GH',
+ 'English (India, with rupee)': 'IN (Eng)',
+ 'English (intl., with AltGr dead keys)': 'US (Altgr-Intl)',
+ 'English (Macintosh)': 'US (Mac)',
+ 'English (Mali, US, intl.)': 'ML (Us-Intl)',
+ 'English (Mali, US, Macintosh)': 'ML (Us-Mac)',
+ 'English (Nigeria)': 'NG',
+ 'English (Norman)': 'US (Norman)',
+ 'English (programmer Dvorak)': 'US (Dvp)',
+ 'English (South Africa)': 'ZA',
+ 'English (the divide/multiply toggle the layout)': 'US (Olpc2)',
+ 'English (UK, Colemak-DH)': 'GB (Colemak Dh)',
+ 'English (UK, Colemak)': 'GB (Colemak)',
+ 'English (UK, Dvorak, with UK punctuation)': 'GB (Dvorakukp)',
+ 'English (UK, Dvorak)': 'GB (Dvorak)',
+ 'English (UK, extended, Windows)': 'GB (Extd)',
+ 'English (UK, intl., with dead keys)': 'GB (Intl)',
+ 'English (UK, Macintosh, intl.)': 'GB (Mac Intl)',
+ 'English (UK, Macintosh)': 'GB (Mac)',
+ 'English (UK)': 'GB',
+ 'English (US, alt. intl.)': 'US (Alt-Intl)',
+ 'English (US, euro on 5)': 'US (Euro)',
+ 'English (US, intl., with dead keys)': 'US (Intl)',
+ 'English (US, Symbolic)': 'US (Symbolic)',
+ 'English (US)': 'US',
+ 'English (Workman, intl., with dead keys)': 'US (Workman-Intl)',
+ 'English (Workman)': 'US (Workman)',
+ Esperanto: 'EPO',
+ 'Esperanto (Brazil, Nativo)': 'BR (Nativo-Epo)',
+ 'Esperanto (legacy)': 'EPO (Legacy)',
+ 'Esperanto (Portugal, Nativo)': 'PT (Nativo-Epo)',
+ Estonian: 'EE',
+ 'Estonian (Dvorak)': 'EE (Dvorak)',
+ 'Estonian (no dead keys)': 'EE (Nodeadkeys)',
+ 'Estonian (US)': 'EE (Us)',
+ Ewe: 'GH (Ewe)',
+ Faroese: 'FO',
+ 'Faroese (no dead keys)': 'FO (Nodeadkeys)',
+ Filipino: 'PH',
+ 'Filipino (Capewell-Dvorak, Baybayin)': 'PH (Capewell-Dvorak-Bay)',
+ 'Filipino (Capewell-Dvorak, Latin)': 'PH (Capewell-Dvorak)',
+ 'Filipino (Capewell-QWERF 2006, Baybayin)': 'PH (Capewell-Qwerf2k6-Bay)',
+ 'Filipino (Capewell-QWERF 2006, Latin)': 'PH (Capewell-Qwerf2k6)',
+ 'Filipino (Colemak, Baybayin)': 'PH (Colemak-Bay)',
+ 'Filipino (Colemak, Latin)': 'PH (Colemak)',
+ 'Filipino (Dvorak, Baybayin)': 'PH (Dvorak-Bay)',
+ 'Filipino (Dvorak, Latin)': 'PH (Dvorak)',
+ 'Filipino (QWERTY, Baybayin)': 'PH (Qwerty-Bay)',
+ Finnish: 'FI',
+ 'Finnish (classic, no dead keys)': 'FI (Nodeadkeys)',
+ 'Finnish (classic)': 'FI (Classic)',
+ 'Finnish (Macintosh)': 'FI (Mac)',
+ 'Finnish (Windows)': 'FI (Winkeys)',
+ French: 'FR',
+ 'French (alt., Latin-9 only)': 'FR (Oss Latin9)',
+ 'French (alt., no dead keys)': 'FR (Oss Nodeadkeys)',
+ 'French (alt.)': 'FR (Oss)',
+ 'French (AZERTY, AFNOR)': 'FR (Afnor)',
+ 'French (AZERTY)': 'FR (Azerty)',
+ 'French (BEPO, AFNOR)': 'FR (Bepo Afnor)',
+ 'French (BEPO, Latin-9 only)': 'FR (Bepo Latin9)',
+ 'French (BEPO)': 'FR (Bepo)',
+ 'French (Cameroon)': 'CM (French)',
+ 'French (Canada, Dvorak)': 'CA (Fr-Dvorak)',
+ 'French (Canada, legacy)': 'CA (Fr-Legacy)',
+ 'French (Canada)': 'CA',
+ 'French (Democratic Republic of the Congo)': 'CD',
+ 'French (Dvorak)': 'FR (Dvorak)',
+ 'French (legacy, alt., no dead keys)': 'FR (Latin9 Nodeadkeys)',
+ 'French (legacy, alt.)': 'FR (Latin9)',
+ 'French (Macintosh)': 'FR (Mac)',
+ 'French (Mali, alt.)': 'ML (Fr-Oss)',
+ 'French (Morocco)': 'MA (French)',
+ 'French (no dead keys)': 'FR (Nodeadkeys)',
+ 'French (Switzerland, Macintosh)': 'CH (Fr Mac)',
+ 'French (Switzerland, no dead keys)': 'CH (Fr Nodeadkeys)',
+ 'French (Switzerland)': 'CH (Fr)',
+ 'French (Togo)': 'TG',
+ 'French (US)': 'FR (Us)',
+ 'Friulian (Italy)': 'IT (Fur)',
+ Fula: 'GH (Fula)',
+ Ga: 'GH (Ga)',
+ Georgian: 'GE',
+ 'Georgian (ergonomic)': 'GE (Ergonomic)',
+ 'Georgian (France, AZERTY Tskapo)': 'FR (Geo)',
+ 'Georgian (Italy)': 'IT (Geo)',
+ 'Georgian (MESS)': 'GE (Mess)',
+ German: 'DE',
+ 'German (Austria, Macintosh)': 'AT (Mac)',
+ 'German (Austria, no dead keys)': 'AT (Nodeadkeys)',
+ 'German (Austria)': 'AT',
+ 'German (dead acute)': 'DE (Deadacute)',
+ 'German (dead grave acute)': 'DE (Deadgraveacute)',
+ 'German (dead tilde)': 'DE (Deadtilde)',
+ 'German (Dvorak)': 'DE (Dvorak)',
+ 'German (E1)': 'DE (E1)',
+ 'German (E2)': 'DE (E2)',
+ 'German (Macintosh, no dead keys)': 'DE (Mac Nodeadkeys)',
+ 'German (Macintosh)': 'DE (Mac)',
+ 'German (Neo 2)': 'DE (Neo)',
+ 'German (no dead keys)': 'DE (Nodeadkeys)',
+ 'German (QWERTY)': 'DE (Qwerty)',
+ 'German (Switzerland, legacy)': 'CH (Legacy)',
+ 'German (Switzerland, Macintosh)': 'CH (De Mac)',
+ 'German (Switzerland, no dead keys)': 'CH (De Nodeadkeys)',
+ 'German (Switzerland)': 'CH',
+ 'German (T3)': 'DE (T3)',
+ 'German (US)': 'DE (Us)',
+ Greek: 'GR',
+ 'Greek (extended)': 'GR (Extended)',
+ 'Greek (no dead keys)': 'GR (Nodeadkeys)',
+ 'Greek (polytonic)': 'GR (Polytonic)',
+ 'Greek (simple)': 'GR (Simple)',
+ Gujarati: 'IN (Guj)',
+ 'Hanyu Pinyin Letters (with AltGr dead keys)': 'CN (Altgr-Pinyin)',
+ 'Hausa (Ghana)': 'GH (Hausa)',
+ 'Hausa (Nigeria)': 'NG (Hausa)',
+ Hawaiian: 'US (Haw)',
+ Hebrew: 'IL',
+ 'Hebrew (Biblical, Tiro)': 'IL (Biblical)',
+ 'Hebrew (lyx)': 'IL (Lyx)',
+ 'Hebrew (phonetic)': 'IL (Phonetic)',
+ 'Hindi (Bolnagri)': 'IN (Bolnagri)',
+ 'Hindi (KaGaPa, phonetic)': 'IN (Hin-Kagapa)',
+ 'Hindi (Wx)': 'IN (Hin-Wx)',
+ Hungarian: 'HU',
+ 'Hungarian (no dead keys)': 'HU (Nodeadkeys)',
+ 'Hungarian (QWERTY, 101-key, comma, dead keys)': 'HU (101 Qwerty Comma Dead)',
+ 'Hungarian (QWERTY, 101-key, comma, no dead keys)': 'HU (101 Qwerty Comma Nodead)',
+ 'Hungarian (QWERTY, 101-key, dot, dead keys)': 'HU (101 Qwerty Dot Dead)',
+ 'Hungarian (QWERTY, 101-key, dot, no dead keys)': 'HU (101 Qwerty Dot Nodead)',
+ 'Hungarian (QWERTY, 102-key, comma, dead keys)': 'HU (102 Qwerty Comma Dead)',
+ 'Hungarian (QWERTY, 102-key, comma, no dead keys)': 'HU (102 Qwerty Comma Nodead)',
+ 'Hungarian (QWERTY, 102-key, dot, dead keys)': 'HU (102 Qwerty Dot Dead)',
+ 'Hungarian (QWERTY, 102-key, dot, no dead keys)': 'HU (102 Qwerty Dot Nodead)',
+ 'Hungarian (QWERTY)': 'HU (Qwerty)',
+ 'Hungarian (QWERTZ, 101-key, comma, dead keys)': 'HU (101 Qwertz Comma Dead)',
+ 'Hungarian (QWERTZ, 101-key, comma, no dead keys)': 'HU (101 Qwertz Comma Nodead)',
+ 'Hungarian (QWERTZ, 101-key, dot, dead keys)': 'HU (101 Qwertz Dot Dead)',
+ 'Hungarian (QWERTZ, 101-key, dot, no dead keys)': 'HU (101 Qwertz Dot Nodead)',
+ 'Hungarian (QWERTZ, 102-key, comma, dead keys)': 'HU (102 Qwertz Comma Dead)',
+ 'Hungarian (QWERTZ, 102-key, comma, no dead keys)': 'HU (102 Qwertz Comma Nodead)',
+ 'Hungarian (QWERTZ, 102-key, dot, dead keys)': 'HU (102 Qwertz Dot Dead)',
+ 'Hungarian (QWERTZ, 102-key, dot, no dead keys)': 'HU (102 Qwertz Dot Nodead)',
+ 'Hungarian (standard)': 'HU (Standard)',
+ Icelandic: 'IS',
+ 'Icelandic (Dvorak)': 'IS (Dvorak)',
+ 'Icelandic (Macintosh, legacy)': 'IS (Mac Legacy)',
+ 'Icelandic (Macintosh)': 'IS (Mac)',
+ Igbo: 'NG (Igbo)',
+ Indian: 'IN',
+ 'Indic IPA': 'IN (Iipa)',
+ 'Indonesian (Arab Melayu, extended phonetic)': 'ID (Melayu-Phoneticx)',
+ 'Indonesian (Arab Melayu, phonetic)': 'ID (Melayu-Phonetic)',
+ 'Indonesian (Arab Pegon, phonetic)': 'ID (Pegon-Phonetic)',
+ 'Indonesian (Latin)': 'ID',
+ Inuktitut: 'CA (Ike)',
+ Iraqi: 'IQ',
+ Irish: 'IE',
+ 'Irish (UnicodeExpert)': 'IE (UnicodeExpert)',
+ Italian: 'IT',
+ 'Italian (IBM 142)': 'IT (Ibm)',
+ 'Italian (intl., with dead keys)': 'IT (Intl)',
+ 'Italian (Macintosh)': 'IT (Mac)',
+ 'Italian (no dead keys)': 'IT (Nodeadkeys)',
+ 'Italian (US)': 'IT (Us)',
+ 'Italian (Windows)': 'IT (Winkeys)',
+ Japanese: 'JP',
+ 'Japanese (Dvorak)': 'JP (Dvorak)',
+ 'Japanese (Kana 86)': 'JP (Kana86)',
+ 'Japanese (Kana)': 'JP (Kana)',
+ 'Japanese (Macintosh)': 'JP (Mac)',
+ 'Japanese (OADG 109A)': 'JP (OADG109A)',
+ Javanese: 'ID (Javanese)',
+ 'Kabyle (AZERTY, with dead keys)': 'DZ (Azerty-Deadkeys)',
+ 'Kabyle (QWERTY, UK, with dead keys)': 'DZ (Qwerty-Gb-Deadkeys)',
+ 'Kabyle (QWERTY, US, with dead keys)': 'DZ (Qwerty-Us-Deadkeys)',
+ Kalmyk: 'RU (Xal)',
+ Kannada: 'IN (Kan)',
+ 'Kannada (KaGaPa, phonetic)': 'IN (Kan-Kagapa)',
+ Kashubian: 'PL (Csb)',
+ Kazakh: 'KZ',
+ 'Kazakh (extended)': 'KZ (Ext)',
+ 'Kazakh (Latin)': 'KZ (Latin)',
+ 'Kazakh (with Russian)': 'KZ (Kazrus)',
+ 'Khmer (Cambodia)': 'KH',
+ Kikuyu: 'KE (Kik)',
+ Komi: 'RU (Kom)',
+ Korean: 'KR',
+ 'Korean (101/104-key compatible)': 'KR (Kr104)',
+ 'Kurdish (Iran, Arabic-Latin)': 'IR (Ku Ara)',
+ 'Kurdish (Iran, F)': 'IR (Ku F)',
+ 'Kurdish (Iran, Latin Alt-Q)': 'IR (Ku Alt)',
+ 'Kurdish (Iran, Latin Q)': 'IR (Ku)',
+ 'Kurdish (Iraq, Arabic-Latin)': 'IQ (Ku Ara)',
+ 'Kurdish (Iraq, F)': 'IQ (Ku F)',
+ 'Kurdish (Iraq, Latin Alt-Q)': 'IQ (Ku Alt)',
+ 'Kurdish (Iraq, Latin Q)': 'IQ (Ku)',
+ 'Kurdish (Syria, F)': 'SY (Ku F)',
+ 'Kurdish (Syria, Latin Alt-Q)': 'SY (Ku Alt)',
+ 'Kurdish (Syria, Latin Q)': 'SY (Ku)',
+ 'Kurdish (Turkey, F)': 'TR (Ku F)',
+ 'Kurdish (Turkey, Latin Alt-Q)': 'TR (Ku Alt)',
+ 'Kurdish (Turkey, Latin Q)': 'TR (Ku)',
+ Kyrgyz: 'KG',
+ 'Kyrgyz (phonetic)': 'KG (Phonetic)',
+ Lao: 'LA',
+ 'Lao (STEA)': 'LA (Stea)',
+ Latvian: 'LV',
+ 'Latvian (adapted)': 'LV (Adapted)',
+ 'Latvian (apostrophe)': 'LV (Apostrophe)',
+ 'Latvian (ergonomic, ŪGJRMV)': 'LV (Ergonomic)',
+ 'Latvian (F)': 'LV (Fkey)',
+ 'Latvian (modern)': 'LV (Modern)',
+ 'Latvian (tilde)': 'LV (Tilde)',
+ Lithuanian: 'LT',
+ 'Lithuanian (IBM LST 1205-92)': 'LT (Ibm)',
+ 'Lithuanian (LEKP)': 'LT (Lekp)',
+ 'Lithuanian (LEKPa)': 'LT (Lekpa)',
+ 'Lithuanian (Ratise)': 'LT (Ratise)',
+ 'Lithuanian (standard)': 'LT (Std)',
+ 'Lithuanian (US)': 'LT (Us)',
+ 'Lower Sorbian': 'DE (Dsb)',
+ 'Lower Sorbian (QWERTZ)': 'DE (Dsb Qwertz)',
+ Macedonian: 'MK',
+ 'Macedonian (no dead keys)': 'MK (Nodeadkeys)',
+ 'Malay (Jawi, Arabic Keyboard)': 'MY',
+ 'Malay (Jawi, phonetic)': 'MY (Phonetic)',
+ Malayalam: 'IN (Mal)',
+ 'Malayalam (enhanced InScript, with rupee)': 'IN (Mal Enhanced)',
+ 'Malayalam (Lalitha)': 'IN (Mal Lalitha)',
+ Maltese: 'MT',
+ 'Maltese (UK, with AltGr overrides)': 'MT (Alt-Gb)',
+ 'Maltese (US, with AltGr overrides)': 'MT (Alt-Us)',
+ 'Maltese (US)': 'MT (Us)',
+ 'Manipuri (Eeyek)': 'IN (Eeyek)',
+ Maori: 'MAO',
+ 'Marathi (enhanced InScript)': 'IN (Marathi)',
+ 'Marathi (KaGaPa, phonetic)': 'IN (Mar-Kagapa)',
+ Mari: 'RU (Chm)',
+ Mmuock: 'CM (Mmuock)',
+ Moldavian: 'MD',
+ 'Moldavian (Gagauz)': 'MD (Gag)',
+ Mon: 'MM (Mnw)',
+ 'Mon (A1)': 'MM (Mnw-A1)',
+ Mongolian: 'MN',
+ 'Mongolian (Bichig)': 'CN (Mon Trad)',
+ 'Mongolian (Galik)': 'CN (Mon Trad Galik)',
+ 'Mongolian (Manchu Galik)': 'CN (Mon Manchu Galik)',
+ 'Mongolian (Manchu)': 'CN (Mon Trad Manchu)',
+ 'Mongolian (Todo Galik)': 'CN (Mon Todo Galik)',
+ 'Mongolian (Todo)': 'CN (Mon Trad Todo)',
+ 'Mongolian (Xibe)': 'CN (Mon Trad Xibe)',
+ Montenegrin: 'ME',
+ 'Montenegrin (Cyrillic, with guillemets)': 'ME (Cyrillicalternatequotes)',
+ 'Montenegrin (Cyrillic, ZE and ZHE swapped)': 'ME (Cyrillicyz)',
+ 'Montenegrin (Cyrillic)': 'ME (Cyrillic)',
+ 'Montenegrin (Latin, QWERTY)': 'ME (Latinyz)',
+ 'Montenegrin (Latin, Unicode, QWERTY)': 'ME (Latinunicodeyz)',
+ 'Montenegrin (Latin, Unicode)': 'ME (Latinunicode)',
+ 'Montenegrin (Latin, with guillemets)': 'ME (Latinalternatequotes)',
+ "N'Ko (AZERTY)": 'GN',
+ Nepali: 'NP',
+ 'Northern Saami (Finland)': 'FI (Smi)',
+ 'Northern Saami (Norway, no dead keys)': 'NO (Smi Nodeadkeys)',
+ 'Northern Saami (Norway)': 'NO (Smi)',
+ 'Northern Saami (Sweden)': 'SE (Smi)',
+ Norwegian: 'NO',
+ 'Norwegian (Colemak)': 'NO (Colemak)',
+ 'Norwegian (Dvorak)': 'NO (Dvorak)',
+ 'Norwegian (Macintosh, no dead keys)': 'NO (Mac Nodeadkeys)',
+ 'Norwegian (Macintosh)': 'NO (Mac)',
+ 'Norwegian (no dead keys)': 'NO (Nodeadkeys)',
+ 'Norwegian (Windows)': 'NO (Winkeys)',
+ Occitan: 'FR (Oci)',
+ Ogham: 'IE (Ogam)',
+ 'Ogham (IS434)': 'IE (Ogam Is434)',
+ 'Ol Chiki': 'IN (Olck)',
+ 'Old Turkic': 'TR (Otk)',
+ 'Old Turkic (F)': 'TR (Otkf)',
+ Oriya: 'IN (Ori)',
+ 'Oriya (Bolnagri)': 'IN (Ori-Bolnagri)',
+ 'Oriya (Wx)': 'IN (Ori-Wx)',
+ 'Ossetian (Georgia)': 'GE (Os)',
+ 'Ossetian (legacy)': 'RU (Os Legacy)',
+ 'Ossetian (Windows)': 'RU (Os Winkeys)',
+ 'Ottoman (F)': 'TR (Otf)',
+ 'Ottoman (Q)': 'TR (Ot)',
+ 'Pannonian Rusyn': 'RS (Rue)',
+ Pashto: 'AF (Ps)',
+ 'Pashto (Afghanistan, OLPC)': 'AF (Ps-Olpc)',
+ Persian: 'IR',
+ 'Persian (with Persian keypad)': 'IR (Pes Keypad)',
+ Polish: 'PL',
+ 'Polish (British keyboard)': 'GB (Pl)',
+ 'Polish (Dvorak, with Polish quotes on key 1)': 'PL (Dvorak Altquotes)',
+ 'Polish (Dvorak, with Polish quotes on quotemark key)': 'PL (Dvorak Quotes)',
+ 'Polish (Dvorak)': 'PL (Dvorak)',
+ 'Polish (legacy)': 'PL (Legacy)',
+ 'Polish (programmer Dvorak)': 'PL (Dvp)',
+ 'Polish (QWERTZ)': 'PL (Qwertz)',
+ Portuguese: 'PT',
+ 'Portuguese (Brazil, Dvorak)': 'BR (Dvorak)',
+ 'Portuguese (Brazil, IBM/Lenovo ThinkPad)': 'BR (Thinkpad)',
+ 'Portuguese (Brazil, Nativo for US keyboards)': 'BR (Nativo-Us)',
+ 'Portuguese (Brazil, Nativo)': 'BR (Nativo)',
+ 'Portuguese (Brazil, no dead keys)': 'BR (Nodeadkeys)',
+ 'Portuguese (Brazil)': 'BR',
+ 'Portuguese (Macintosh, no dead keys)': 'PT (Mac Nodeadkeys)',
+ 'Portuguese (Macintosh)': 'PT (Mac)',
+ 'Portuguese (Nativo for US keyboards)': 'PT (Nativo-Us)',
+ 'Portuguese (Nativo)': 'PT (Nativo)',
+ 'Portuguese (no dead keys)': 'PT (Nodeadkeys)',
+ 'Punjabi (Gurmukhi Jhelum)': 'IN (Jhelum)',
+ 'Punjabi (Gurmukhi)': 'IN (Guru)',
+ Romanian: 'RO',
+ 'Romanian (Germany, no dead keys)': 'DE (Ro Nodeadkeys)',
+ 'Romanian (Germany)': 'DE (Ro)',
+ 'Romanian (standard)': 'RO (Std)',
+ 'Romanian (Windows)': 'RO (Winkeys)',
+ Russian: 'RU',
+ 'Russian (Belarus)': 'BY (Ru)',
+ 'Russian (Czech, phonetic)': 'CZ (Rus)',
+ 'Russian (DOS)': 'RU (Dos)',
+ 'Russian (engineering, EN)': 'RU (Ruchey En)',
+ 'Russian (engineering, RU)': 'RU (Ruchey Ru)',
+ 'Russian (Georgia)': 'GE (Ru)',
+ 'Russian (Germany, phonetic)': 'DE (Ru)',
+ 'Russian (Kazakhstan, with Kazakh)': 'KZ (Ruskaz)',
+ 'Russian (legacy)': 'RU (Legacy)',
+ 'Russian (Macintosh)': 'RU (Mac)',
+ 'Russian (phonetic, AZERTY)': 'RU (Phonetic Azerty)',
+ 'Russian (phonetic, Dvorak)': 'RU (Phonetic Dvorak)',
+ 'Russian (phonetic, French)': 'RU (Phonetic Fr)',
+ 'Russian (phonetic, Windows)': 'RU (Phonetic Winkeys)',
+ 'Russian (phonetic, YAZHERTY)': 'RU (Phonetic YAZHERTY)',
+ 'Russian (phonetic)': 'RU (Phonetic)',
+ 'Russian (Poland, phonetic Dvorak)': 'PL (Ru Phonetic Dvorak)',
+ 'Russian (Sweden, phonetic, no dead keys)': 'SE (Rus Nodeadkeys)',
+ 'Russian (Sweden, phonetic)': 'SE (Rus)',
+ 'Russian (typewriter, legacy)': 'RU (Typewriter-Legacy)',
+ 'Russian (typewriter)': 'RU (Typewriter)',
+ 'Russian (Ukraine, standard RSTU)': 'UA (Rstu Ru)',
+ 'Russian (US, phonetic)': 'US (Rus)',
+ 'Saisiyat (Taiwan)': 'TW (Saisiyat)',
+ Samogitian: 'LT (Sgs)',
+ 'Sanskrit (KaGaPa, phonetic)': 'IN (San-Kagapa)',
+ 'Scottish Gaelic': 'GB (Gla)',
+ Serbian: 'RS',
+ 'Serbian (Cyrillic, with guillemets)': 'RS (Alternatequotes)',
+ 'Serbian (Cyrillic, ZE and ZHE swapped)': 'RS (Yz)',
+ 'Serbian (Latin, QWERTY)': 'RS (Latinyz)',
+ 'Serbian (Latin, Unicode, QWERTY)': 'RS (Latinunicodeyz)',
+ 'Serbian (Latin, Unicode)': 'RS (Latinunicode)',
+ 'Serbian (Latin, with guillemets)': 'RS (Latinalternatequotes)',
+ 'Serbian (Latin)': 'RS (Latin)',
+ 'Serbian (Russia)': 'RU (Srp)',
+ 'Serbo-Croatian (US)': 'US (Hbs)',
+ Shan: 'MM (Shn)',
+ 'Shan (Zawgyi Tai)': 'MM (Zgt)',
+ Sicilian: 'IT (Scn)',
+ Silesian: 'PL (Szl)',
+ Sindhi: 'PK (Snd)',
+ 'Sinhala (phonetic)': 'LK',
+ 'Sinhala (US)': 'LK (Us)',
+ Slovak: 'SK',
+ 'Slovak (extended backslash)': 'SK (Bksl)',
+ 'Slovak (QWERTY, extended backslash)': 'SK (Qwerty Bksl)',
+ 'Slovak (QWERTY)': 'SK (Qwerty)',
+ Slovenian: 'SI',
+ 'Slovenian (US)': 'SI (Us)',
+ 'Slovenian (with guillemets)': 'SI (Alternatequotes)',
+ Spanish: 'ES',
+ 'Spanish (dead tilde)': 'ES (Deadtilde)',
+ 'Spanish (Dvorak)': 'ES (Dvorak)',
+ 'Spanish (Latin American, Colemak)': 'LATAM (Colemak)',
+ 'Spanish (Latin American, dead tilde)': 'LATAM (Deadtilde)',
+ 'Spanish (Latin American, Dvorak)': 'LATAM (Dvorak)',
+ 'Spanish (Latin American, no dead keys)': 'LATAM (Nodeadkeys)',
+ 'Spanish (Latin American)': 'LATAM',
+ 'Spanish (Macintosh)': 'ES (Mac)',
+ 'Spanish (no dead keys)': 'ES (Nodeadkeys)',
+ 'Spanish (Windows)': 'ES (Winkeys)',
+ 'Swahili (Kenya)': 'KE',
+ 'Swahili (Tanzania)': 'TZ',
+ Swedish: 'SE',
+ 'Swedish (Dvorak, intl.)': 'SE (Us Dvorak)',
+ 'Swedish (Dvorak)': 'SE (Dvorak)',
+ 'Swedish (Macintosh)': 'SE (Mac)',
+ 'Swedish (no dead keys)': 'SE (Nodeadkeys)',
+ 'Swedish (Svdvorak)': 'SE (Svdvorak)',
+ 'Swedish (US)': 'SE (Us)',
+ 'Swedish Sign Language': 'SE (Swl)',
+ Syriac: 'SY (Syc)',
+ 'Syriac (phonetic)': 'SY (Syc Phonetic)',
+ Taiwanese: 'TW',
+ 'Taiwanese (indigenous)': 'TW (Indigenous)',
+ Tajik: 'TJ',
+ 'Tajik (legacy)': 'TJ (Legacy)',
+ 'Tamil (InScript, with Arabic numerals)': 'IN (Tam)',
+ 'Tamil (InScript, with Tamil numerals)': 'IN (Tam Tamilnumbers)',
+ "Tamil (Sri Lanka, TamilNet '99, TAB encoding)": 'LK (Tam TAB)',
+ "Tamil (Sri Lanka, TamilNet '99)": 'LK (Tam Unicode)',
+ "Tamil (TamilNet '99 with Tamil numerals)": 'IN (Tamilnet Tamilnumbers)',
+ "Tamil (TamilNet '99, TAB encoding)": 'IN (Tamilnet TAB)',
+ "Tamil (TamilNet '99, TSCII encoding)": 'IN (Tamilnet TSCII)',
+ "Tamil (TamilNet '99)": 'IN (Tamilnet)',
+ Tarifit: 'MA (Rif)',
+ Tatar: 'RU (Tt)',
+ Telugu: 'IN (Tel)',
+ 'Telugu (KaGaPa, phonetic)': 'IN (Tel-Kagapa)',
+ 'Telugu (Sarala)': 'IN (Tel-Sarala)',
+ Thai: 'TH',
+ 'Thai (Pattachote)': 'TH (Pat)',
+ 'Thai (TIS-820.2538)': 'TH (Tis)',
+ Tibetan: 'CN (Tib)',
+ 'Tibetan (with ASCII numerals)': 'CN (Tib Asciinum)',
+ Tswana: 'BW',
+ Turkish: 'TR',
+ 'Turkish (Alt-Q)': 'TR (Alt)',
+ 'Turkish (E)': 'TR (E)',
+ 'Turkish (F)': 'TR (F)',
+ 'Turkish (Germany)': 'DE (Tr)',
+ 'Turkish (intl., with dead keys)': 'TR (Intl)',
+ Turkmen: 'TM',
+ 'Turkmen (Alt-Q)': 'TM (Alt)',
+ Udmurt: 'RU (Udm)',
+ Ukrainian: 'UA',
+ 'Ukrainian (homophonic)': 'UA (Homophonic)',
+ 'Ukrainian (legacy)': 'UA (Legacy)',
+ 'Ukrainian (macOS)': 'UA (MacOS)',
+ 'Ukrainian (phonetic)': 'UA (Phonetic)',
+ 'Ukrainian (standard RSTU)': 'UA (Rstu)',
+ 'Ukrainian (typewriter)': 'UA (Typewriter)',
+ 'Ukrainian (Windows)': 'UA (Winkeys)',
+ 'Urdu (alt. phonetic)': 'IN (Urd-Phonetic3)',
+ 'Urdu (Pakistan, CRULP)': 'PK (Urd-Crulp)',
+ 'Urdu (Pakistan, NLA)': 'PK (Urd-Nla)',
+ 'Urdu (Pakistan)': 'PK',
+ 'Urdu (phonetic)': 'IN (Urd-Phonetic)',
+ 'Urdu (Windows)': 'IN (Urd-Winkeys)',
+ Uyghur: 'CN (Ug)',
+ Uzbek: 'UZ',
+ 'Uzbek (Afghanistan, OLPC)': 'AF (Uz-Olpc)',
+ 'Uzbek (Afghanistan)': 'AF (Uz)',
+ 'Uzbek (Latin)': 'UZ (Latin)',
+ Vietnamese: 'VN',
+ 'Vietnamese (France)': 'VN (Fr)',
+ 'Vietnamese (US)': 'VN (Us)',
+ Wolof: 'SN',
+ Yakut: 'RU (Sah)',
+ Yoruba: 'NG (Yoruba)',
+ 'Unknown Layout': 'Unknown',
+} as const;
diff --git a/customModules/module.ts b/customModules/module.ts
index 1578334..5438ade 100644
--- a/customModules/module.ts
+++ b/customModules/module.ts
@@ -1,8 +1,9 @@
-import { Module } from "lib/types/bar";
-import options from "options";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
-import { Binding } from "types/service";
-import { Variable as VariableType } from "types/variable";
+import { BarBoxChild, Module } from 'lib/types/bar';
+import { BarButtonStyles } from 'lib/types/options';
+import { Bind } from 'lib/types/variable';
+import { GtkWidget } from 'lib/types/widget';
+import options from 'options';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
const { style } = options.theme.bar.buttons;
@@ -15,68 +16,69 @@ export const module = ({
tooltipText,
boxClass,
props = {},
- showLabelBinding = undefinedVar.bind("value"),
+ showLabelBinding = undefinedVar.bind('value'),
showLabel,
labelHook,
- hook
-}: Module) => {
- const getIconWidget = () => {
+ hook,
+}: Module): BarBoxChild => {
+ const getIconWidget = (): GtkWidget | undefined => {
let iconWidget: Gtk.Widget | undefined;
if (icon !== undefined) {
iconWidget = Widget.Icon({
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
- icon: icon
+ icon: icon,
}) as unknown as Gtk.Widget;
} else if (textIcon !== undefined) {
iconWidget = Widget.Label({
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
- label: textIcon
+ label: textIcon,
}) as unknown as Gtk.Widget;
}
return iconWidget;
- }
+ };
return {
component: Widget.Box({
- className: Utils.merge([style.bind("value"), showLabelBinding], (style: string, shwLabel: boolean) => {
- const shouldShowLabel = shwLabel || showLabel;
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
- return `${boxClass} ${styleMap[style]} ${!shouldShowLabel ? "no-label" : ""}`;
- }),
+ className: Utils.merge(
+ [style.bind('value'), showLabelBinding],
+ (style: BarButtonStyles, shwLabel: boolean) => {
+ const shouldShowLabel = shwLabel || showLabel;
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `${boxClass} ${styleMap[style]} ${!shouldShowLabel ? 'no-label' : ''}`;
+ },
+ ),
tooltip_text: tooltipText,
- children: Utils.merge(
- [showLabelBinding],
- (showLabelBinding): Gtk.Widget[] => {
- const childrenArray: Gtk.Widget[] = [];
- const iconWidget = getIconWidget();
+ children: Utils.merge([showLabelBinding], (showLabelBinding): Gtk.Widget[] => {
+ const childrenArray: Gtk.Widget[] = [];
+ const iconWidget = getIconWidget();
- if (iconWidget !== undefined) {
- childrenArray.push(iconWidget);
- }
-
- if (showLabelBinding) {
- childrenArray.push(
- Widget.Label({
- class_name: `bar-button-label module-label ${boxClass}`,
- label: label,
- setup: labelHook,
- }) as unknown as Gtk.Widget
- );
- }
- return childrenArray;
+ if (iconWidget !== undefined) {
+ childrenArray.push(iconWidget);
}
- ) as Binding, any, Gtk.Widget[]>,
+
+ if (showLabelBinding) {
+ childrenArray.push(
+ Widget.Label({
+ class_name: `bar-button-label module-label ${boxClass}`,
+ label: label,
+ setup: labelHook,
+ }) as unknown as Gtk.Widget,
+ );
+ }
+ return childrenArray;
+ }) as Bind,
setup: hook,
}),
tooltip_text: tooltipText,
isVisible: true,
boxClass,
- props
+ props,
};
};
diff --git a/customModules/netstat/computeNetwork.ts b/customModules/netstat/computeNetwork.ts
index 94e4103..e1b2dcd 100644
--- a/customModules/netstat/computeNetwork.ts
+++ b/customModules/netstat/computeNetwork.ts
@@ -71,7 +71,11 @@ const getNetworkUsage = (interfaceName: string = ''): NetworkUsage => {
return { name: '', rx: 0, tx: 0 };
};
-export const computeNetwork = (round: VariableType, interfaceNameVar: VariableType, dataType: VariableType): NetworkResourceData => {
+export const computeNetwork = (
+ round: VariableType,
+ interfaceNameVar: VariableType,
+ dataType: VariableType,
+): NetworkResourceData => {
const rateUnit = dataType.value;
const interfaceName = interfaceNameVar ? interfaceNameVar.value : '';
diff --git a/customModules/netstat/index.ts b/customModules/netstat/index.ts
index ea80354..fce6f1c 100644
--- a/customModules/netstat/index.ts
+++ b/customModules/netstat/index.ts
@@ -2,7 +2,7 @@ import options from 'options';
import { module } from '../module';
import { inputHandler } from 'customModules/utils';
import { computeNetwork } from './computeNetwork';
-import { NetstatLabelType } from 'lib/types/bar';
+import { Module, NetstatLabelType } from 'lib/types/bar';
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
import Button from 'types/widgets/button';
import { NetworkResourceData } from 'lib/types/customModules/network';
@@ -23,9 +23,7 @@ const {
pollingInterval,
} = options.bar.customModules.netstat;
-export const networkUsage = Variable(
- GET_DEFAULT_NETSTAT_DATA(rateUnit.value),
-);
+export const networkUsage = Variable(GET_DEFAULT_NETSTAT_DATA(rateUnit.value));
pollVariable(
// Variable to poll and update with the result of the function passed in
@@ -48,11 +46,8 @@ pollVariable(
rateUnit,
);
-export const Netstat = () => {
- const renderNetworkLabel = (
- lblType: NetstatLabelType,
- network: NetworkResourceData,
- ): string => {
+export const Netstat = (): Module => {
+ const renderNetworkLabel = (lblType: NetstatLabelType, network: NetworkResourceData): string => {
switch (lblType) {
case 'in':
return `↓ ${network.in}`;
@@ -88,19 +83,17 @@ export const Netstat = () => {
},
onScrollUp: {
fn: () => {
- labelType.value =
- NETWORK_LABEL_TYPES[
+ labelType.value = NETWORK_LABEL_TYPES[
(NETWORK_LABEL_TYPES.indexOf(labelType.value) + 1) % NETWORK_LABEL_TYPES.length
- ] as NetstatLabelType;
+ ] as NetstatLabelType;
},
},
onScrollDown: {
fn: () => {
- labelType.value =
- NETWORK_LABEL_TYPES[
+ labelType.value = NETWORK_LABEL_TYPES[
(NETWORK_LABEL_TYPES.indexOf(labelType.value) - 1 + NETWORK_LABEL_TYPES.length) %
- NETWORK_LABEL_TYPES.length
- ] as NetstatLabelType;
+ NETWORK_LABEL_TYPES.length
+ ] as NetstatLabelType;
},
},
});
@@ -110,4 +103,3 @@ export const Netstat = () => {
return netstatModule;
};
-
diff --git a/customModules/power/index.ts b/customModules/power/index.ts
index 5cbb575..2170571 100644
--- a/customModules/power/index.ts
+++ b/customModules/power/index.ts
@@ -1,24 +1,18 @@
-import options from "options";
-import { module } from "../module"
+import options from 'options';
+import { module } from '../module';
-import { inputHandler } from "customModules/utils";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
-import Button from "types/widgets/button";
+import { inputHandler } from 'customModules/utils';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
+import Button from 'types/widgets/button';
+import { Module } from 'lib/types/bar';
-const {
- icon,
- leftClick,
- rightClick,
- middleClick,
- scrollUp,
- scrollDown,
-} = options.bar.customModules.power;
+const { icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.power;
-export const Power = () => {
+export const Power = (): Module => {
const powerModule = module({
- tooltipText: "Power Menu",
- textIcon: icon.bind("value"),
- boxClass: "powermodule",
+ tooltipText: 'Power Menu',
+ textIcon: icon.bind('value'),
+ boxClass: 'powermodule',
props: {
setup: (self: Button) => {
inputHandler(self, {
@@ -43,4 +37,4 @@ export const Power = () => {
});
return powerModule;
-}
+};
diff --git a/customModules/ram/computeRam.ts b/customModules/ram/computeRam.ts
index 8e8a03e..b8026c2 100644
--- a/customModules/ram/computeRam.ts
+++ b/customModules/ram/computeRam.ts
@@ -1,9 +1,10 @@
const GLib = imports.gi.GLib;
import { divide } from 'customModules/utils';
+import { GenericResourceData } from 'lib/types/customModules/generic';
import { Variable as VariableType } from 'types/variable';
-export const calculateRamUsage = (round: VariableType) => {
+export const calculateRamUsage = (round: VariableType): GenericResourceData => {
try {
const [success, meminfoBytes] = GLib.file_get_contents('/proc/meminfo');
@@ -26,17 +27,14 @@ export const calculateRamUsage = (round: VariableType) => {
let usedRam = totalRamInBytes - availableRamInBytes;
usedRam = isNaN(usedRam) || usedRam < 0 ? 0 : usedRam;
-
return {
percentage: divide([totalRamInBytes, usedRam], round.value),
total: totalRamInBytes,
used: usedRam,
free: availableRamInBytes,
};
-
} catch (error) {
console.error('Error calculating RAM usage:', error);
- return { total: 0, used: 0, percentage: 0 };
+ return { total: 0, used: 0, percentage: 0, free: 0 };
}
};
-
diff --git a/customModules/ram/index.ts b/customModules/ram/index.ts
index e479d78..58fb075 100644
--- a/customModules/ram/index.ts
+++ b/customModules/ram/index.ts
@@ -1,62 +1,48 @@
-import options from "options";
+import options from 'options';
// Module initializer
-import { module } from "../module"
+import { module } from '../module';
// Types
-import { GenericResourceData } from "lib/types/customModules/generic";
-import Button from "types/widgets/button";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
+import { GenericResourceData } from 'lib/types/customModules/generic';
+import Button from 'types/widgets/button';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
// Helper Methods
-import { calculateRamUsage } from "./computeRam";
+import { calculateRamUsage } from './computeRam';
// Utility Methods
-import { formatTooltip, inputHandler, renderResourceLabel } from "customModules/utils";
-import { ResourceLabelType } from "lib/types/bar";
+import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
+import { Module, ResourceLabelType } from 'lib/types/bar';
// Global Constants
-import { LABEL_TYPES } from "lib/types/defaults/bar";
-import { pollVariable } from "customModules/PollVar";
+import { LABEL_TYPES } from 'lib/types/defaults/bar';
+import { pollVariable } from 'customModules/PollVar';
// All the user configurable options for the ram module that are needed
-const {
- label,
- labelType,
- round,
- leftClick,
- rightClick,
- middleClick,
- pollingInterval
-} = options.bar.customModules.ram;
+const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval } = options.bar.customModules.ram;
const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 };
-const ramUsage = Variable(defaultRamData);
+const ramUsage = Variable(defaultRamData);
-pollVariable(
- ramUsage,
- [round.bind('value')],
- pollingInterval.bind('value'),
- calculateRamUsage,
- round,
-);
-
-export const Ram = () => {
+pollVariable(ramUsage, [round.bind('value')], pollingInterval.bind('value'), calculateRamUsage, round);
+export const Ram = (): Module => {
const ramModule = module({
- textIcon: "",
+ textIcon: '',
label: Utils.merge(
- [ramUsage.bind("value"), labelType.bind("value"), round.bind("value")],
+ [ramUsage.bind('value'), labelType.bind('value'), round.bind('value')],
(rmUsg: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
const returnValue = renderResourceLabel(lblTyp, rmUsg, round);
return returnValue;
- }),
- tooltipText: labelType.bind("value").as(lblTyp => {
+ },
+ ),
+ tooltipText: labelType.bind('value').as((lblTyp) => {
return formatTooltip('RAM', lblTyp);
}),
- boxClass: "ram",
- showLabelBinding: label.bind("value"),
+ boxClass: 'ram',
+ showLabelBinding: label.bind('value'),
props: {
setup: (self: Button) => {
inputHandler(self, {
@@ -71,18 +57,22 @@ export const Ram = () => {
},
onScrollUp: {
fn: () => {
- labelType.value = LABEL_TYPES[(LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length] as ResourceLabelType;
- }
+ labelType.value = LABEL_TYPES[
+ (LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length
+ ] as ResourceLabelType;
+ },
},
onScrollDown: {
fn: () => {
- labelType.value = LABEL_TYPES[(LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length] as ResourceLabelType;
- }
+ labelType.value = LABEL_TYPES[
+ (LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length
+ ] as ResourceLabelType;
+ },
},
});
},
- }
+ },
});
return ramModule;
-}
+};
diff --git a/customModules/storage/computeStorage.ts b/customModules/storage/computeStorage.ts
index 17e11fd..49cbc14 100644
--- a/customModules/storage/computeStorage.ts
+++ b/customModules/storage/computeStorage.ts
@@ -1,23 +1,20 @@
-// @ts-expect-error
+// @ts-expect-error is a special directive that tells the compiler to use the GTop library
import GTop from 'gi://GTop';
import { divide } from 'customModules/utils';
import { Variable as VariableType } from 'types/variable';
+import { GenericResourceData } from 'lib/types/customModules/generic';
-let previousFsUsage = new GTop.glibtop_fsusage();
-
-export const computeStorage = (round: VariableType) => {
+export const computeStorage = (round: VariableType): GenericResourceData => {
try {
const currentFsUsage = new GTop.glibtop_fsusage();
- GTop.glibtop_get_fsusage(currentFsUsage, "/");
+ GTop.glibtop_get_fsusage(currentFsUsage, '/');
const total = currentFsUsage.blocks * currentFsUsage.block_size;
const available = currentFsUsage.bavail * currentFsUsage.block_size;
const used = total - available;
- previousFsUsage = currentFsUsage;
-
return {
total,
used,
@@ -26,7 +23,6 @@ export const computeStorage = (round: VariableType) => {
};
} catch (error) {
console.error('Error calculating RAM usage:', error);
- return { total: 0, used: 0, percentage: 0 };
+ return { total: 0, used: 0, percentage: 0, free: 0 };
}
};
-
diff --git a/customModules/storage/index.ts b/customModules/storage/index.ts
index 2188c45..eed1f01 100644
--- a/customModules/storage/index.ts
+++ b/customModules/storage/index.ts
@@ -1,52 +1,38 @@
-import options from "options";
-import { module } from "../module"
+import options from 'options';
+import { module } from '../module';
-import { formatTooltip, inputHandler, renderResourceLabel } from "customModules/utils";
-import { computeStorage } from "./computeStorage";
-import { ResourceLabelType } from "lib/types/bar";
-import { GenericResourceData } from "lib/types/customModules/generic";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
-import Button from "types/widgets/button";
-import { LABEL_TYPES } from "lib/types/defaults/bar";
-import { pollVariable } from "customModules/PollVar";
+import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
+import { computeStorage } from './computeStorage';
+import { Module, ResourceLabelType } from 'lib/types/bar';
+import { GenericResourceData } from 'lib/types/customModules/generic';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
+import Button from 'types/widgets/button';
+import { LABEL_TYPES } from 'lib/types/defaults/bar';
+import { pollVariable } from 'customModules/PollVar';
-const {
- label,
- labelType,
- icon,
- round,
- leftClick,
- rightClick,
- middleClick,
- pollingInterval
-} = options.bar.customModules.storage;
+const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } =
+ options.bar.customModules.storage;
const defaultStorageData = { total: 0, used: 0, percentage: 0, free: 0 };
-const storageUsage = Variable(defaultStorageData);
+const storageUsage = Variable(defaultStorageData);
-pollVariable(
- storageUsage,
- [round.bind('value')],
- pollingInterval.bind('value'),
- computeStorage,
- round,
-);
+pollVariable(storageUsage, [round.bind('value')], pollingInterval.bind('value'), computeStorage, round);
-export const Storage = () => {
+export const Storage = (): Module => {
const storageModule = module({
- textIcon: icon.bind("value"),
+ textIcon: icon.bind('value'),
label: Utils.merge(
- [storageUsage.bind("value"), labelType.bind("value"), round.bind("value")],
+ [storageUsage.bind('value'), labelType.bind('value'), round.bind('value')],
(storage: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
return renderResourceLabel(lblTyp, storage, round);
- }),
- tooltipText: labelType.bind("value").as(lblTyp => {
+ },
+ ),
+ tooltipText: labelType.bind('value').as((lblTyp) => {
return formatTooltip('Storage', lblTyp);
-
}),
- boxClass: "storage",
- showLabelBinding: label.bind("value"),
+ boxClass: 'storage',
+ showLabelBinding: label.bind('value'),
props: {
setup: (self: Button) => {
inputHandler(self, {
@@ -61,18 +47,22 @@ export const Storage = () => {
},
onScrollUp: {
fn: () => {
- labelType.value = LABEL_TYPES[(LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length] as ResourceLabelType;
- }
+ labelType.value = LABEL_TYPES[
+ (LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length
+ ] as ResourceLabelType;
+ },
},
onScrollDown: {
fn: () => {
- labelType.value = LABEL_TYPES[(LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length] as ResourceLabelType;
- }
+ labelType.value = LABEL_TYPES[
+ (LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length
+ ] as ResourceLabelType;
+ },
},
});
},
- }
+ },
});
return storageModule;
-}
+};
diff --git a/customModules/theme.ts b/customModules/theme.ts
index b3b025c..3e3008f 100644
--- a/customModules/theme.ts
+++ b/customModules/theme.ts
@@ -1,106 +1,146 @@
-import { Option } from "widget/settings/shared/Option";
-import { Header } from "widget/settings/shared/Header";
+import { Option } from 'widget/settings/shared/Option';
+import { Header } from 'widget/settings/shared/Header';
-import options from "options";
+import options from 'options';
+import Scrollable from 'types/widgets/scrollable';
+import { Attribute, GtkWidget } from 'lib/types/widget';
-export const CustomModuleTheme = () => {
+export const CustomModuleTheme = (): Scrollable => {
return Widget.Scrollable({
- vscroll: "automatic",
- hscroll: "automatic",
- class_name: "menu-theme-page customModules paged-container",
+ vscroll: 'automatic',
+ hscroll: 'automatic',
+ class_name: 'menu-theme-page customModules paged-container',
child: Widget.Box({
- class_name: "bar-theme-page paged-container",
+ class_name: 'bar-theme-page paged-container',
vertical: true,
children: [
Header('RAM'),
Option({ opt: options.theme.bar.buttons.modules.ram.text, title: 'Text', type: 'color' }),
Option({ opt: options.theme.bar.buttons.modules.ram.icon, title: 'Icon', type: 'color' }),
- Option({ opt: options.theme.bar.buttons.modules.ram.background, title: 'Label Background', type: 'color' }),
+ Option({
+ opt: options.theme.bar.buttons.modules.ram.background,
+ title: 'Label Background',
+ type: 'color',
+ }),
Option({
opt: options.theme.bar.buttons.modules.ram.icon_background,
title: 'Icon Background',
- subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
- type: 'color'
+ subtitle:
+ "Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
+ type: 'color',
}),
Header('CPU'),
Option({ opt: options.theme.bar.buttons.modules.cpu.text, title: 'Text', type: 'color' }),
Option({ opt: options.theme.bar.buttons.modules.cpu.icon, title: 'Icon', type: 'color' }),
- Option({ opt: options.theme.bar.buttons.modules.cpu.background, title: 'Label Background', type: 'color' }),
+ Option({
+ opt: options.theme.bar.buttons.modules.cpu.background,
+ title: 'Label Background',
+ type: 'color',
+ }),
Option({
opt: options.theme.bar.buttons.modules.cpu.icon_background,
title: 'Icon Background',
- subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
- type: 'color'
+ subtitle:
+ "Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
+ type: 'color',
}),
Header('Storage'),
Option({ opt: options.theme.bar.buttons.modules.storage.text, title: 'Text', type: 'color' }),
Option({ opt: options.theme.bar.buttons.modules.storage.icon, title: 'Icon', type: 'color' }),
- Option({ opt: options.theme.bar.buttons.modules.storage.background, title: 'Label Background', type: 'color' }),
+ Option({
+ opt: options.theme.bar.buttons.modules.storage.background,
+ title: 'Label Background',
+ type: 'color',
+ }),
Option({
opt: options.theme.bar.buttons.modules.storage.icon_background,
title: 'Icon Background',
- subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
- type: 'color'
+ subtitle:
+ "Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
+ type: 'color',
}),
Header('Netstat'),
Option({ opt: options.theme.bar.buttons.modules.netstat.text, title: 'Text', type: 'color' }),
Option({ opt: options.theme.bar.buttons.modules.netstat.icon, title: 'Icon', type: 'color' }),
- Option({ opt: options.theme.bar.buttons.modules.netstat.background, title: 'Label Background', type: 'color' }),
+ Option({
+ opt: options.theme.bar.buttons.modules.netstat.background,
+ title: 'Label Background',
+ type: 'color',
+ }),
Option({
opt: options.theme.bar.buttons.modules.netstat.icon_background,
title: 'Icon Background',
- subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
- type: 'color'
+ subtitle:
+ "Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
+ type: 'color',
}),
Header('Keyboard Layout'),
Option({ opt: options.theme.bar.buttons.modules.kbLayout.text, title: 'Text', type: 'color' }),
Option({ opt: options.theme.bar.buttons.modules.kbLayout.icon, title: 'Icon', type: 'color' }),
- Option({ opt: options.theme.bar.buttons.modules.kbLayout.background, title: 'Label Background', type: 'color' }),
+ Option({
+ opt: options.theme.bar.buttons.modules.kbLayout.background,
+ title: 'Label Background',
+ type: 'color',
+ }),
Option({
opt: options.theme.bar.buttons.modules.kbLayout.icon_background,
title: 'Icon Background',
- subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
- type: 'color'
+ subtitle:
+ "Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
+ type: 'color',
}),
Header('Updates'),
Option({ opt: options.theme.bar.buttons.modules.updates.text, title: 'Text', type: 'color' }),
Option({ opt: options.theme.bar.buttons.modules.updates.icon, title: 'Icon', type: 'color' }),
- Option({ opt: options.theme.bar.buttons.modules.updates.background, title: 'Label Background', type: 'color' }),
+ Option({
+ opt: options.theme.bar.buttons.modules.updates.background,
+ title: 'Label Background',
+ type: 'color',
+ }),
Option({
opt: options.theme.bar.buttons.modules.updates.icon_background,
title: 'Icon Background',
- subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
- type: 'color'
+ subtitle:
+ "Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
+ type: 'color',
}),
Header('Weather'),
Option({ opt: options.theme.bar.buttons.modules.weather.icon, title: 'Icon', type: 'color' }),
Option({ opt: options.theme.bar.buttons.modules.weather.text, title: 'Text', type: 'color' }),
- Option({ opt: options.theme.bar.buttons.modules.weather.background, title: 'Label Background', type: 'color' }),
+ Option({
+ opt: options.theme.bar.buttons.modules.weather.background,
+ title: 'Label Background',
+ type: 'color',
+ }),
Option({
opt: options.theme.bar.buttons.modules.weather.icon_background,
title: 'Icon Background',
- subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
- type: 'color'
+ subtitle:
+ "Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
+ type: 'color',
}),
Header('Power'),
Option({ opt: options.theme.bar.buttons.modules.power.icon, title: 'Icon', type: 'color' }),
- Option({ opt: options.theme.bar.buttons.modules.power.background, title: 'Label Background', type: 'color' }),
+ Option({
+ opt: options.theme.bar.buttons.modules.power.background,
+ title: 'Label Background',
+ type: 'color',
+ }),
Option({
opt: options.theme.bar.buttons.modules.power.icon_background,
title: 'Icon Background',
- subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
- type: 'color'
+ subtitle:
+ "Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
+ type: 'color',
}),
- ]
- })
- })
-}
-
-
+ ],
+ }),
+ });
+};
diff --git a/customModules/updates/index.ts b/customModules/updates/index.ts
index 944a28e..c427fd3 100644
--- a/customModules/updates/index.ts
+++ b/customModules/updates/index.ts
@@ -1,11 +1,12 @@
-import options from "options";
-import { module } from "../module"
+import options from 'options';
+import { module } from '../module';
-import { inputHandler } from "customModules/utils";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
-import Button from "types/widgets/button";
-import { Variable as VariableType } from "types/variable";
-import { pollVariableBash } from "customModules/PollVar";
+import { inputHandler } from 'customModules/utils';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
+import Button from 'types/widgets/button';
+import { Variable as VariableType } from 'types/variable';
+import { pollVariableBash } from 'customModules/PollVar';
+import { Module } from 'lib/types/bar';
const {
updateCommand,
@@ -20,12 +21,12 @@ const {
scrollDown,
} = options.bar.customModules.updates;
-const pendingUpdates: VariableType = Variable(" 0");
+const pendingUpdates: VariableType = Variable(' 0');
-const processUpdateCount = (updateCount: string) => {
+const processUpdateCount = (updateCount: string): string => {
if (!padZero.value) return updateCount;
return `${updateCount.padStart(2, '0')}`;
-}
+};
pollVariableBash(
pendingUpdates,
@@ -35,13 +36,13 @@ pollVariableBash(
processUpdateCount,
);
-export const Updates = () => {
+export const Updates = (): Module => {
const updatesModule = module({
- textIcon: icon.bind("value"),
- tooltipText: pendingUpdates.bind("value").as(v => `${v} updates available`),
- boxClass: "updates",
- label: pendingUpdates.bind("value"),
- showLabelBinding: label.bind("value"),
+ textIcon: icon.bind('value'),
+ tooltipText: pendingUpdates.bind('value').as((v) => `${v} updates available`),
+ boxClass: 'updates',
+ label: pendingUpdates.bind('value'),
+ showLabelBinding: label.bind('value'),
props: {
setup: (self: Button) => {
inputHandler(self, {
@@ -66,7 +67,4 @@ export const Updates = () => {
});
return updatesModule;
-}
-
-
-
+};
diff --git a/customModules/utils.ts b/customModules/utils.ts
index 63bf4e1..20679ab 100644
--- a/customModules/utils.ts
+++ b/customModules/utils.ts
@@ -1,5 +1,8 @@
import { ResourceLabelType } from 'lib/types/bar';
-import { GenericResourceData } from 'lib/types/customModules/generic';
+import { GenericResourceData, Postfix } from 'lib/types/customModules/generic';
+import { InputHandlerEvents } from 'lib/types/customModules/utils';
+import { ThrottleFn, ThrottleFnCallback } from 'lib/types/utils';
+import { GtkWidget } from 'lib/types/widget';
import { Binding } from 'lib/utils';
import { openMenu } from 'modules/bar/utils';
import options from 'options';
@@ -12,14 +15,11 @@ const { scrollSpeed } = options.bar.customModules;
export const runAsyncCommand = (
cmd: string,
- fn: Function,
- events: { clicked: any; event: Gdk.Event }
+ fn: (output: string) => void,
+ events: { clicked: Button; event: Gdk.Event },
): void => {
if (cmd.startsWith('menu:')) {
- // if the command starts with 'menu:', then it is a menu command
- // and we should App.toggleMenu("menuName") based on the input menu:menuName. Ignoring spaces and case
const menuName = cmd.split(':')[1].trim().toLowerCase();
-
openMenu(events.clicked, events.event, `${menuName}menu`);
return;
@@ -31,15 +31,10 @@ export const runAsyncCommand = (
fn(output);
}
})
- .catch((err) =>
- console.error(`Error running command "${cmd}": ${err})`)
- );
+ .catch((err) => console.error(`Error running command "${cmd}": ${err})`));
};
-export function throttle void>(
- func: T,
- limit: number
-): T {
+export function throttle(func: T, limit: number): T {
let inThrottle: boolean;
return function (this: ThisParameterType, ...args: Parameters) {
if (!inThrottle) {
@@ -52,31 +47,23 @@ export function throttle void>(
} as T;
}
-export const throttledScrollHandler = (interval: number) =>
- throttle((cmd: string, fn: Function | undefined) => {
+export const throttledScrollHandler = (interval: number): ThrottleFn =>
+ throttle((cmd: string, fn: ThrottleFnCallback) => {
Utils.execAsync(`bash -c "${cmd}"`)
.then((output) => {
if (fn !== undefined) {
fn(output);
}
})
- .catch((err) =>
- console.error(`Error running command "${cmd}": ${err}`)
- );
+ .catch((err) => console.error(`Error running command "${cmd}": ${err}`));
}, 200 / interval);
const dummyVar = Variable('');
export const inputHandler = (
self: Button,
- {
- onPrimaryClick,
- onSecondaryClick,
- onMiddleClick,
- onScrollUp,
- onScrollDown,
- }
-) => {
+ { onPrimaryClick, onSecondaryClick, onMiddleClick, onScrollUp, onScrollDown }: InputHandlerEvents,
+): void => {
const sanitizeInput = (input: VariableType): string => {
if (input === undefined) {
return '';
@@ -88,46 +75,25 @@ export const inputHandler = (
const interval = scrollSpeed.value;
const throttledHandler = throttledScrollHandler(interval);
- self.on_primary_click = (clicked: any, event: Gdk.Event) =>
- runAsyncCommand(
- sanitizeInput(onPrimaryClick?.cmd || dummyVar),
- onPrimaryClick.fn,
- { clicked, event }
- );
+ self.on_primary_click = (clicked: Button, event: Gdk.Event): void =>
+ runAsyncCommand(sanitizeInput(onPrimaryClick?.cmd || dummyVar), onPrimaryClick.fn, { clicked, event });
- self.on_secondary_click = (clicked: any, event: Gdk.Event) =>
- runAsyncCommand(
- sanitizeInput(onSecondaryClick?.cmd || dummyVar),
- onSecondaryClick.fn,
- { clicked, event }
- );
+ self.on_secondary_click = (clicked: Button, event: Gdk.Event): void =>
+ runAsyncCommand(sanitizeInput(onSecondaryClick?.cmd || dummyVar), onSecondaryClick.fn, { clicked, event });
- self.on_middle_click = (clicked: any, event: Gdk.Event) =>
- runAsyncCommand(
- sanitizeInput(onMiddleClick?.cmd || dummyVar),
- onMiddleClick.fn,
- { clicked, event }
- );
+ self.on_middle_click = (clicked: Button, event: Gdk.Event): void =>
+ runAsyncCommand(sanitizeInput(onMiddleClick?.cmd || dummyVar), onMiddleClick.fn, { clicked, event });
- self.on_scroll_up = () =>
- throttledHandler(
- sanitizeInput(onScrollUp?.cmd || dummyVar),
- onScrollUp.fn
- );
+ self.on_scroll_up = (): void => throttledHandler(sanitizeInput(onScrollUp?.cmd || dummyVar), onScrollUp.fn);
- self.on_scroll_down = () =>
- throttledHandler(
- sanitizeInput(onScrollDown?.cmd || dummyVar),
- onScrollDown.fn
- );
+ self.on_scroll_down = (): void =>
+ throttledHandler(sanitizeInput(onScrollDown?.cmd || dummyVar), onScrollDown.fn);
};
// Initial setup of event handlers
updateHandlers();
- const sanitizeVariable = (
- someVar: VariableType | undefined
- ): Binding => {
+ const sanitizeVariable = (someVar: VariableType | undefined): Binding => {
if (someVar === undefined || typeof someVar.bind !== 'function') {
return dummyVar.bind('value');
}
@@ -144,37 +110,36 @@ export const inputHandler = (
sanitizeVariable(onScrollUp),
sanitizeVariable(onScrollDown),
],
- updateHandlers
+ updateHandlers,
);
};
-export const divide = ([total, used]: number[], round: boolean) => {
+export const divide = ([total, used]: number[], round: boolean): number => {
const percentageTotal = (used / total) * 100;
if (round) {
return total > 0 ? Math.round(percentageTotal) : 0;
}
return total > 0 ? parseFloat(percentageTotal.toFixed(2)) : 0;
-
};
-export const formatSizeInKiB = (sizeInBytes: number, round: boolean) => {
- const sizeInGiB = sizeInBytes / (1024 ** 1);
+export const formatSizeInKiB = (sizeInBytes: number, round: boolean): number => {
+ const sizeInGiB = sizeInBytes / 1024 ** 1;
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
};
-export const formatSizeInMiB = (sizeInBytes: number, round: boolean) => {
- const sizeInGiB = sizeInBytes / (1024 ** 2);
+export const formatSizeInMiB = (sizeInBytes: number, round: boolean): number => {
+ const sizeInGiB = sizeInBytes / 1024 ** 2;
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
};
-export const formatSizeInGiB = (sizeInBytes: number, round: boolean) => {
- const sizeInGiB = sizeInBytes / (1024 ** 3);
+export const formatSizeInGiB = (sizeInBytes: number, round: boolean): number => {
+ const sizeInGiB = sizeInBytes / 1024 ** 3;
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
};
-export const formatSizeInTiB = (sizeInBytes: number, round: boolean) => {
- const sizeInGiB = sizeInBytes / (1024 ** 4);
+export const formatSizeInTiB = (sizeInBytes: number, round: boolean): number => {
+ const sizeInGiB = sizeInBytes / 1024 ** 4;
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
};
-export const autoFormatSize = (sizeInBytes: number, round: boolean) => {
+export const autoFormatSize = (sizeInBytes: number, round: boolean): number => {
// auto convert to GiB, MiB, KiB, TiB, or bytes
if (sizeInBytes >= 1024 ** 4) return formatSizeInTiB(sizeInBytes, round);
if (sizeInBytes >= 1024 ** 3) return formatSizeInGiB(sizeInBytes, round);
@@ -182,22 +147,18 @@ export const autoFormatSize = (sizeInBytes: number, round: boolean) => {
if (sizeInBytes >= 1024 ** 1) return formatSizeInKiB(sizeInBytes, round);
return sizeInBytes;
-}
+};
-export const getPostfix = (sizeInBytes: number) => {
+export const getPostfix = (sizeInBytes: number): Postfix => {
if (sizeInBytes >= 1024 ** 4) return 'TiB';
if (sizeInBytes >= 1024 ** 3) return 'GiB';
if (sizeInBytes >= 1024 ** 2) return 'MiB';
if (sizeInBytes >= 1024 ** 1) return 'KiB';
return 'B';
-}
+};
-export const renderResourceLabel = (
- lblType: ResourceLabelType,
- rmUsg: GenericResourceData,
- round: boolean
-) => {
+export const renderResourceLabel = (lblType: ResourceLabelType, rmUsg: GenericResourceData, round: boolean): string => {
const { used, total, percentage, free } = rmUsg;
const formatFunctions = {
@@ -205,7 +166,7 @@ export const renderResourceLabel = (
GiB: formatSizeInGiB,
MiB: formatSizeInMiB,
KiB: formatSizeInKiB,
- B: (size: number, _: boolean) => size
+ B: (size: number): number => size,
};
// Get them datas in proper GiB, MiB, KiB, TiB, or bytes
@@ -217,20 +178,20 @@ export const renderResourceLabel = (
const formatUsed = formatFunctions[postfix] || formatFunctions['B'];
const usedSizeFormatted = formatUsed(used, round);
- if (lblType === "used/total") {
+ if (lblType === 'used/total') {
return `${usedSizeFormatted}/${totalSizeFormatted} ${postfix}`;
}
- if (lblType === "used") {
+ if (lblType === 'used') {
return `${autoFormatSize(used, round)} ${getPostfix(used)}`;
}
- if (lblType === "free") {
+ if (lblType === 'free') {
return `${autoFormatSize(free, round)} ${getPostfix(free)}`;
}
return `${percentage}%`;
};
-export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType) => {
+export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType): string => {
switch (lblTyp) {
case 'used':
return `Used ${dataType}`;
@@ -243,4 +204,4 @@ export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType) => {
default:
return '';
}
-}
+};
diff --git a/customModules/weather/index.ts b/customModules/weather/index.ts
index 2fa55e7..9cd4ff1 100644
--- a/customModules/weather/index.ts
+++ b/customModules/weather/index.ts
@@ -1,41 +1,30 @@
-import options from "options";
-import { module } from "../module"
+import options from 'options';
+import { module } from '../module';
-import { inputHandler } from "customModules/utils";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
-import Button from "types/widgets/button";
-import { getWeatherStatusIcon, globalWeatherVar } from "globals/weather";
+import { inputHandler } from 'customModules/utils';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
+import Button from 'types/widgets/button';
+import { getWeatherStatusTextIcon, globalWeatherVar } from 'globals/weather';
+import { Module } from 'lib/types/bar';
-const {
- label,
- unit,
- leftClick,
- rightClick,
- middleClick,
- scrollUp,
- scrollDown,
-} = options.bar.customModules.weather;
+const { label, unit, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.weather;
-export const Weather = () => {
-
- const networkModule = module({
- icon: Utils.merge([globalWeatherVar.bind("value")], (wthr) => {
- const weatherStatusIcon = getWeatherStatusIcon(wthr);
+export const Weather = (): Module => {
+ const weatherModule = module({
+ textIcon: Utils.merge([globalWeatherVar.bind('value')], (wthr) => {
+ const weatherStatusIcon = getWeatherStatusTextIcon(wthr);
return weatherStatusIcon;
}),
- tooltipText: globalWeatherVar.bind("value").as(v => `Weather Status: ${v.current.condition.text}`),
- boxClass: "weather-custom",
- label: Utils.merge(
- [globalWeatherVar.bind("value"), unit.bind("value")],
- (wthr, unt) => {
- if (unt === "imperial") {
- return `${Math.ceil(wthr.current.temp_f)}° F`;
- } else {
- return `${Math.ceil(wthr.current.temp_c)}° C`;
- }
- },
- ),
- showLabelBinding: label.bind("value"),
+ tooltipText: globalWeatherVar.bind('value').as((v) => `Weather Status: ${v.current.condition.text}`),
+ boxClass: 'weather-custom',
+ label: Utils.merge([globalWeatherVar.bind('value'), unit.bind('value')], (wthr, unt) => {
+ if (unt === 'imperial') {
+ return `${Math.ceil(wthr.current.temp_f)}° F`;
+ } else {
+ return `${Math.ceil(wthr.current.temp_c)}° C`;
+ }
+ }),
+ showLabelBinding: label.bind('value'),
props: {
setup: (self: Button) => {
inputHandler(self, {
@@ -59,9 +48,5 @@ export const Weather = () => {
},
});
- return networkModule;
-}
-
-
-
-
+ return weatherModule;
+};
diff --git a/directoryMonitorService.ts b/directoryMonitorService.ts
index 911dc69..2e1a74a 100644
--- a/directoryMonitorService.ts
+++ b/directoryMonitorService.ts
@@ -1,8 +1,8 @@
-import Service from "resource:///com/github/Aylur/ags/service.js";
-import App from "resource:///com/github/Aylur/ags/app.js";
-import { monitorFile } from "resource:///com/github/Aylur/ags/utils.js";
-import Gio from "gi://Gio";
-import { FileInfo } from "types/@girs/gio-2.0/gio-2.0.cjs";
+import Service from 'resource:///com/github/Aylur/ags/service.js';
+import App from 'resource:///com/github/Aylur/ags/app.js';
+import { monitorFile } from 'resource:///com/github/Aylur/ags/utils.js';
+import Gio from 'gi://Gio';
+import { FileInfo } from 'types/@girs/gio-2.0/gio-2.0.cjs';
class DirectoryMonitorService extends Service {
static {
@@ -14,23 +14,19 @@ class DirectoryMonitorService extends Service {
this.recursiveDirectoryMonitor(`${App.configDir}/scss`);
}
- recursiveDirectoryMonitor(directoryPath: string) {
+ recursiveDirectoryMonitor(directoryPath: string): void {
monitorFile(directoryPath, (_, eventType) => {
if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) {
- this.emit("changed");
+ this.emit('changed');
}
});
const directory = Gio.File.new_for_path(directoryPath);
- const enumerator = directory.enumerate_children(
- "standard::*",
- Gio.FileQueryInfoFlags.NONE,
- null,
- );
+ const enumerator = directory.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
let fileInfo: FileInfo;
while ((fileInfo = enumerator.next_file(null) as FileInfo) !== null) {
- const childPath = directoryPath + "/" + fileInfo.get_name();
+ const childPath = directoryPath + '/' + fileInfo.get_name();
if (fileInfo.get_file_type() === Gio.FileType.DIRECTORY) {
this.recursiveDirectoryMonitor(childPath);
}
diff --git a/external/ags-types b/external/ags-types
new file mode 160000
index 0000000..87b5046
--- /dev/null
+++ b/external/ags-types
@@ -0,0 +1 @@
+Subproject commit 87b5046791040615cd65b48a04be062662a46e36
diff --git a/globals.d.ts b/globals.d.ts
new file mode 100644
index 0000000..bc426d4
--- /dev/null
+++ b/globals.d.ts
@@ -0,0 +1,14 @@
+// globals.d.ts
+/* eslint-disable no-var */
+
+import { Options, Variable as VariableType } from 'types/variable';
+
+declare global {
+ var globalMousePos: VariableType;
+ var useTheme: (filePath: string) => void;
+ var globalWeatherVar: VariableType;
+ var options: Options;
+ var removingNotifications: VariableType;
+}
+
+export {};
diff --git a/globals/mousePos.ts b/globals/mousePos.ts
index 7e127a3..390ee30 100644
--- a/globals/mousePos.ts
+++ b/globals/mousePos.ts
@@ -1,3 +1,5 @@
-const globalMousePosVar = Variable([0, 0]);
+import { Variable as VariableType } from 'types/variable';
-globalThis["globalMousePos"] = globalMousePosVar;
+const globalMousePosVar: VariableType = Variable([0, 0]);
+
+globalThis['globalMousePos'] = globalMousePosVar;
diff --git a/globals/network.ts b/globals/network.ts
new file mode 100644
index 0000000..44fbf77
--- /dev/null
+++ b/globals/network.ts
@@ -0,0 +1,15 @@
+export const WIFI_STATUS_MAP = {
+ unknown: 'Status Unknown',
+ unmanaged: 'Unmanaged',
+ unavailable: 'Unavailable',
+ disconnected: 'Disconnected',
+ prepare: 'Preparing Connecting',
+ config: 'Connecting',
+ need_auth: 'Needs Authentication',
+ ip_config: 'Requesting IP',
+ ip_check: 'Checking Access',
+ secondaries: 'Waiting on Secondaries',
+ activated: 'Connected',
+ deactivating: 'Disconnecting',
+ failed: 'Connection Failed',
+} as const;
diff --git a/globals/notification.ts b/globals/notification.ts
new file mode 100644
index 0000000..1564029
--- /dev/null
+++ b/globals/notification.ts
@@ -0,0 +1,37 @@
+import icons from 'modules/icons/index';
+import { Notification } from 'types/service/notifications';
+
+export const removingNotifications = Variable(false);
+
+export const getNotificationIcon = (app_name: string, app_icon: string, app_entry: string): string => {
+ let icon: string = icons.fallback.notification;
+
+ if (Utils.lookUpIcon(app_name) || Utils.lookUpIcon(app_name.toLowerCase() || '')) {
+ icon = Utils.lookUpIcon(app_name)
+ ? app_name
+ : Utils.lookUpIcon(app_name.toLowerCase())
+ ? app_name.toLowerCase()
+ : '';
+ }
+
+ if (Utils.lookUpIcon(app_icon) && icon === '') {
+ icon = app_icon;
+ }
+
+ if (Utils.lookUpIcon(app_entry || '') && icon === '') {
+ icon = app_entry || '';
+ }
+
+ return icon;
+};
+
+export const closeNotifications = async (notifications: Notification[]): Promise => {
+ removingNotifications.value = true;
+ for (const notif of notifications) {
+ notif.close();
+ await new Promise((resolve) => setTimeout(resolve, 100));
+ }
+ removingNotifications.value = false;
+};
+
+globalThis['removingNotifications'] = removingNotifications;
diff --git a/globals/useTheme.ts b/globals/useTheme.ts
index eecf3ac..15c2322 100644
--- a/globals/useTheme.ts
+++ b/globals/useTheme.ts
@@ -1,10 +1,12 @@
-import Gio from "gi://Gio"
-import { bash, Notify } from "lib/utils";
-import icons from "lib/icons"
-import { filterConfigForThemeOnly, loadJsonFile, saveConfigToFile } from "widget/settings/shared/FileChooser";
+import Gio from 'gi://Gio';
+import { bash, Notify } from 'lib/utils';
+import icons from 'lib/icons';
+import { filterConfigForThemeOnly, loadJsonFile, saveConfigToFile } from 'widget/settings/shared/FileChooser';
+
+export const hexColorPattern = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
globalThis.useTheme = (filePath: string): void => {
- let importedConfig = loadJsonFile(filePath);
+ const importedConfig = loadJsonFile(filePath);
if (!importedConfig) {
return;
@@ -14,22 +16,22 @@ globalThis.useTheme = (filePath: string): void => {
summary: `Importing Theme`,
body: `Importing: ${filePath}`,
iconName: icons.ui.info,
- timeout: 7000
+ timeout: 7000,
});
- let tmpConfigFile = Gio.File.new_for_path(`${TMP}/config.json`);
- let optionsConfigFile = Gio.File.new_for_path(OPTIONS);
+ const tmpConfigFile = Gio.File.new_for_path(`${TMP}/config.json`);
+ const optionsConfigFile = Gio.File.new_for_path(OPTIONS);
- let [tmpSuccess, tmpContent] = tmpConfigFile.load_contents(null);
- let [optionsSuccess, optionsContent] = optionsConfigFile.load_contents(null);
+ const [tmpSuccess, tmpContent] = tmpConfigFile.load_contents(null);
+ const [optionsSuccess, optionsContent] = optionsConfigFile.load_contents(null);
if (!tmpSuccess || !optionsSuccess) {
- console.error("Failed to read existing configuration files.");
+ console.error('Failed to read existing configuration files.');
return;
}
- let tmpConfig = JSON.parse(new TextDecoder("utf-8").decode(tmpContent));
- let optionsConfig = JSON.parse(new TextDecoder("utf-8").decode(optionsContent));
+ let tmpConfig = JSON.parse(new TextDecoder('utf-8').decode(tmpContent));
+ let optionsConfig = JSON.parse(new TextDecoder('utf-8').decode(optionsContent));
const filteredConfig = filterConfigForThemeOnly(importedConfig);
tmpConfig = { ...tmpConfig, ...filteredConfig };
@@ -37,6 +39,5 @@ globalThis.useTheme = (filePath: string): void => {
saveConfigToFile(tmpConfig, `${TMP}/config.json`);
saveConfigToFile(optionsConfig, OPTIONS);
- bash("pkill ags && ags");
-}
-
+ bash('pkill ags && ags');
+};
diff --git a/globals/variables.ts b/globals/variables.ts
new file mode 100644
index 0000000..721ddab
--- /dev/null
+++ b/globals/variables.ts
@@ -0,0 +1,13 @@
+import { Opt } from 'lib/option';
+import { HexColor, RecursiveOptionsObject } from 'lib/types/options';
+
+export const isOpt = (value: unknown): value is Opt =>
+ typeof value === 'object' && value !== null && 'value' in value && value instanceof Opt;
+
+export const isRecursiveOptionsObject = (value: unknown): value is RecursiveOptionsObject => {
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
+};
+
+export const isHexColor = (value: string): value is HexColor => {
+ return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value);
+};
diff --git a/globals/weather.ts b/globals/weather.ts
index cd86084..3da7ba1 100644
--- a/globals/weather.ts
+++ b/globals/weather.ts
@@ -1,9 +1,8 @@
-import options from "options";
-import { UnitType, Weather } from "lib/types/weather.js";
-import { DEFAULT_WEATHER } from "lib/types/defaults/weather.js";
-import GLib from "gi://GLib?version=2.0"
-
-import icons from "../modules/icons/index.js";
+import options from 'options';
+import { UnitType, Weather, WeatherIconTitle, WeatherIcon } from 'lib/types/weather.js';
+import { DEFAULT_WEATHER } from 'lib/types/defaults/weather.js';
+import GLib from 'gi://GLib?version=2.0';
+import { weatherIcons } from 'modules/icons/weather.js';
const { key, interval, location } = options.menus.clock.weather;
@@ -11,12 +10,12 @@ export const globalWeatherVar = Variable(DEFAULT_WEATHER);
let weatherIntervalInstance: null | number = null;
-const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: string) => {
+const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: string): void => {
if (weatherIntervalInstance !== null) {
GLib.source_remove(weatherIntervalInstance);
}
- const formattedLocation = loc.replace(" ", "%20");
+ const formattedLocation = loc.replace(' ', '%20');
weatherIntervalInstance = Utils.interval(weatherInterval, () => {
Utils.execAsync(
@@ -24,17 +23,17 @@ const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: str
)
.then((res) => {
try {
- if (typeof res !== "string") {
- return globalWeatherVar.value = DEFAULT_WEATHER;
+ if (typeof res !== 'string') {
+ return (globalWeatherVar.value = DEFAULT_WEATHER);
}
const parsedWeather = JSON.parse(res);
- if (Object.keys(parsedWeather).includes("error")) {
- return globalWeatherVar.value = DEFAULT_WEATHER;
+ if (Object.keys(parsedWeather).includes('error')) {
+ return (globalWeatherVar.value = DEFAULT_WEATHER);
}
- return globalWeatherVar.value = parsedWeather;
+ return (globalWeatherVar.value = parsedWeather);
} catch (error) {
globalWeatherVar.value = DEFAULT_WEATHER;
console.warn(`Failed to parse weather data: ${error}`);
@@ -44,70 +43,80 @@ const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: str
console.error(`Failed to fetch weather: ${err}`);
globalWeatherVar.value = DEFAULT_WEATHER;
});
- })
+ });
};
-Utils.merge([key.bind("value"), interval.bind("value"), location.bind("value")], (weatherKey, weatherInterval, loc) => {
+Utils.merge([key.bind('value'), interval.bind('value'), location.bind('value')], (weatherKey, weatherInterval, loc) => {
if (!weatherKey) {
- return globalWeatherVar.value = DEFAULT_WEATHER;
+ return (globalWeatherVar.value = DEFAULT_WEATHER);
}
weatherIntervalFn(weatherInterval, loc, weatherKey);
});
-export const getTemperature = (wthr: Weather, unt: UnitType) => {
- if (unt === "imperial") {
+export const getTemperature = (wthr: Weather, unt: UnitType): string => {
+ if (unt === 'imperial') {
return `${Math.ceil(wthr.current.temp_f)}° F`;
} else {
return `${Math.ceil(wthr.current.temp_c)}° C`;
}
};
-export const getWeatherIcon = (fahren: number) => {
+export const getWeatherIcon = (fahren: number): Record => {
const icons = {
- 100: "",
- 75: "",
- 50: "",
- 25: "",
- 0: "",
- };
+ 100: '',
+ 75: '',
+ 50: '',
+ 25: '',
+ 0: '',
+ } as const;
const colors = {
- 100: "weather-color red",
- 75: "weather-color orange",
- 50: "weather-color lavender",
- 25: "weather-color blue",
- 0: "weather-color sky",
- };
+ 100: 'weather-color red',
+ 75: 'weather-color orange',
+ 50: 'weather-color lavender',
+ 25: 'weather-color blue',
+ 0: 'weather-color sky',
+ } as const;
- const threshold =
- fahren < 0
- ? 0
- : [100, 75, 50, 25, 0].find((threshold) => threshold <= fahren);
+ type IconKeys = keyof typeof icons;
+
+ const threshold: IconKeys =
+ fahren < 0 ? 0 : ([100, 75, 50, 25, 0] as IconKeys[]).find((threshold) => threshold <= fahren) || 0;
+
+ const icon = icons[threshold || 50];
+ const color = colors[threshold || 50];
return {
- icon: icons[threshold || 50],
- color: colors[threshold || 50],
+ icon,
+ color,
};
};
-export const getWindConditions = (wthr: Weather, unt: UnitType) => {
- if (unt === "imperial") {
+export const getWindConditions = (wthr: Weather, unt: UnitType): string => {
+ if (unt === 'imperial') {
return `${Math.floor(wthr.current.wind_mph)} mph`;
}
return `${Math.floor(wthr.current.wind_kph)} kph`;
-}
-
-export const getRainChance = (wthr: Weather) => `${wthr.forecast.forecastday[0].day.daily_chance_of_rain}%`;
-
-
-export const getWeatherStatusIcon = (wthr: Weather) => {
- let iconQuery = wthr.current.condition.text
- .trim()
- .toLowerCase()
- .replaceAll(" ", "_");
-
- if (!wthr.current.is_day && iconQuery === "partly_cloudy") {
- iconQuery = "partly_cloudy_night";
- }
- return icons.weather[iconQuery];
};
-globalThis["globalWeatherVar"] = globalWeatherVar;
+
+export const getRainChance = (wthr: Weather): string => `${wthr.forecast.forecastday[0].day.daily_chance_of_rain}%`;
+
+export const isValidWeatherIconTitle = (title: string): title is WeatherIconTitle => {
+ return title in weatherIcons;
+};
+
+export const getWeatherStatusTextIcon = (wthr: Weather): WeatherIcon => {
+ let iconQuery = wthr.current.condition.text.trim().toLowerCase().replaceAll(' ', '_');
+
+ if (!wthr.current.is_day && iconQuery === 'partly_cloudy') {
+ iconQuery = 'partly_cloudy_night';
+ }
+
+ if (isValidWeatherIconTitle(iconQuery)) {
+ return weatherIcons[iconQuery];
+ } else {
+ console.warn(`Unknown weather icon title: ${iconQuery}`);
+ return weatherIcons['warning'];
+ }
+};
+
+globalThis['globalWeatherVar'] = globalWeatherVar;
diff --git a/globals/window.ts b/globals/window.ts
new file mode 100644
index 0000000..ae823bb
--- /dev/null
+++ b/globals/window.ts
@@ -0,0 +1,10 @@
+export const WINDOW_LAYOUTS: string[] = [
+ 'center',
+ 'top',
+ 'top-right',
+ 'top-center',
+ 'top-left',
+ 'bottom-left',
+ 'bottom-center',
+ 'bottom-right',
+];
diff --git a/lib/constants/colors.ts b/lib/constants/colors.ts
new file mode 100644
index 0000000..95ac5cf
--- /dev/null
+++ b/lib/constants/colors.ts
@@ -0,0 +1,142 @@
+export const namedColors = new Set([
+ 'alice blue',
+ 'antique white',
+ 'aqua',
+ 'aquamarine',
+ 'azure',
+ 'beige',
+ 'bisque',
+ 'black',
+ 'blanched almond',
+ 'blue',
+ 'blue violet',
+ 'brown',
+ 'burlywood',
+ 'cadet blue',
+ 'chartreuse',
+ 'chocolate',
+ 'coral',
+ 'cornflower blue',
+ 'cornsilk',
+ 'crimson',
+ 'cyan',
+ 'dark blue',
+ 'dark cyan',
+ 'dark goldenrod',
+ 'dark gray',
+ 'dark green',
+ 'dark khaki',
+ 'dark magenta',
+ 'dark olive green',
+ 'dark orange',
+ 'dark orchid',
+ 'dark red',
+ 'dark salmon',
+ 'dark sea green',
+ 'dark slate blue',
+ 'dark slate gray',
+ 'dark turquoise',
+ 'dark violet',
+ 'deep pink',
+ 'deep sky blue',
+ 'dim gray',
+ 'dodger blue',
+ 'firebrick',
+ 'floral white',
+ 'forest green',
+ 'fuchsia',
+ 'gainsboro',
+ 'ghost white',
+ 'gold',
+ 'goldenrod',
+ 'gray',
+ 'green',
+ 'green yellow',
+ 'honeydew',
+ 'hot pink',
+ 'indian red',
+ 'indigo',
+ 'ivory',
+ 'khaki',
+ 'lavender',
+ 'lavender blush',
+ 'lawn green',
+ 'lemon chiffon',
+ 'light blue',
+ 'light coral',
+ 'light cyan',
+ 'light goldenrod yellow',
+ 'light green',
+ 'light grey',
+ 'light pink',
+ 'light salmon',
+ 'light sea green',
+ 'light sky blue',
+ 'light slate gray',
+ 'light steel blue',
+ 'light yellow',
+ 'lime',
+ 'lime green',
+ 'linen',
+ 'magenta',
+ 'maroon',
+ 'medium aquamarine',
+ 'medium blue',
+ 'medium orchid',
+ 'medium purple',
+ 'medium sea green',
+ 'medium slate blue',
+ 'medium spring green',
+ 'medium turquoise',
+ 'medium violet red',
+ 'midnight blue',
+ 'mint cream',
+ 'misty rose',
+ 'moccasin',
+ 'navajo white',
+ 'navy',
+ 'old lace',
+ 'olive',
+ 'olive drab',
+ 'orange',
+ 'orange red',
+ 'orchid',
+ 'pale goldenrod',
+ 'pale green',
+ 'pale turquoise',
+ 'pale violet red',
+ 'papaya whip',
+ 'peach puff',
+ 'peru',
+ 'pink',
+ 'plum',
+ 'powder blue',
+ 'purple',
+ 'red',
+ 'rosy brown',
+ 'royal blue',
+ 'saddle brown',
+ 'salmon',
+ 'sandy brown',
+ 'sea green',
+ 'seashell',
+ 'sienna',
+ 'silver',
+ 'sky blue',
+ 'slate blue',
+ 'slate gray',
+ 'snow',
+ 'spring green',
+ 'steel blue',
+ 'tan',
+ 'teal',
+ 'thistle',
+ 'tomato',
+ 'turquoise',
+ 'violet',
+ 'wheat',
+ 'white',
+ 'white smoke',
+ 'yellow',
+ 'yellow green',
+]);
diff --git a/lib/icons.ts b/lib/icons.ts
index f6da697..8813940 100644
--- a/lib/icons.ts
+++ b/lib/icons.ts
@@ -1,145 +1,145 @@
export const substitutes = {
- "transmission-gtk": "transmission",
- "blueberry.py": "blueberry",
- "Caprine": "facebook-messenger",
- "com.raggesilver.BlackBox-symbolic": "terminal-symbolic",
- "org.wezfurlong.wezterm-symbolic": "terminal-symbolic",
- "audio-headset-bluetooth": "audio-headphones-symbolic",
- "audio-card-analog-usb": "audio-speakers-symbolic",
- "audio-card-analog-pci": "audio-card-symbolic",
- "preferences-system": "emblem-system-symbolic",
- "com.github.Aylur.ags-symbolic": "controls-symbolic",
- "com.github.Aylur.ags": "controls-symbolic",
-}
+ 'transmission-gtk': 'transmission',
+ 'blueberry.py': 'blueberry',
+ Caprine: 'facebook-messenger',
+ 'com.raggesilver.BlackBox-symbolic': 'terminal-symbolic',
+ 'org.wezfurlong.wezterm-symbolic': 'terminal-symbolic',
+ 'audio-headset-bluetooth': 'audio-headphones-symbolic',
+ 'audio-card-analog-usb': 'audio-speakers-symbolic',
+ 'audio-card-analog-pci': 'audio-card-symbolic',
+ 'preferences-system': 'emblem-system-symbolic',
+ 'com.github.Aylur.ags-symbolic': 'controls-symbolic',
+ 'com.github.Aylur.ags': 'controls-symbolic',
+} as const;
export default {
- missing: "image-missing-symbolic",
+ missing: 'image-missing-symbolic',
nix: {
- nix: "nix-snowflake-symbolic",
+ nix: 'nix-snowflake-symbolic',
},
app: {
- terminal: "terminal-symbolic",
+ terminal: 'terminal-symbolic',
},
fallback: {
- executable: "application-x-executable",
- notification: "dialog-information-symbolic",
- video: "video-x-generic-symbolic",
- audio: "audio-x-generic-symbolic",
+ executable: 'application-x-executable',
+ notification: 'dialog-information-symbolic',
+ video: 'video-x-generic-symbolic',
+ audio: 'audio-x-generic-symbolic',
},
ui: {
- close: "window-close-symbolic",
- colorpicker: "color-select-symbolic",
- info: "info-symbolic",
- link: "external-link-symbolic",
- lock: "system-lock-screen-symbolic",
- menu: "open-menu-symbolic",
- refresh: "view-refresh-symbolic",
- search: "system-search-symbolic",
- settings: "emblem-system-symbolic",
- themes: "preferences-desktop-theme-symbolic",
- tick: "object-select-symbolic",
- time: "hourglass-symbolic",
- toolbars: "toolbars-symbolic",
- warning: "dialog-warning-symbolic",
- avatar: "avatar-default-symbolic",
+ close: 'window-close-symbolic',
+ colorpicker: 'color-select-symbolic',
+ info: 'info-symbolic',
+ link: 'external-link-symbolic',
+ lock: 'system-lock-screen-symbolic',
+ menu: 'open-menu-symbolic',
+ refresh: 'view-refresh-symbolic',
+ search: 'system-search-symbolic',
+ settings: 'emblem-system-symbolic',
+ themes: 'preferences-desktop-theme-symbolic',
+ tick: 'object-select-symbolic',
+ time: 'hourglass-symbolic',
+ toolbars: 'toolbars-symbolic',
+ warning: 'dialog-warning-symbolic',
+ avatar: 'avatar-default-symbolic',
arrow: {
- right: "pan-end-symbolic",
- left: "pan-start-symbolic",
- down: "pan-down-symbolic",
- up: "pan-up-symbolic",
+ right: 'pan-end-symbolic',
+ left: 'pan-start-symbolic',
+ down: 'pan-down-symbolic',
+ up: 'pan-up-symbolic',
},
},
audio: {
mic: {
- muted: "microphone-disabled-symbolic",
- low: "microphone-sensitivity-low-symbolic",
- medium: "microphone-sensitivity-medium-symbolic",
- high: "microphone-sensitivity-high-symbolic",
+ muted: 'microphone-disabled-symbolic',
+ low: 'microphone-sensitivity-low-symbolic',
+ medium: 'microphone-sensitivity-medium-symbolic',
+ high: 'microphone-sensitivity-high-symbolic',
},
volume: {
- muted: "audio-volume-muted-symbolic",
- low: "audio-volume-low-symbolic",
- medium: "audio-volume-medium-symbolic",
- high: "audio-volume-high-symbolic",
- overamplified: "audio-volume-overamplified-symbolic",
+ muted: 'audio-volume-muted-symbolic',
+ low: 'audio-volume-low-symbolic',
+ medium: 'audio-volume-medium-symbolic',
+ high: 'audio-volume-high-symbolic',
+ overamplified: 'audio-volume-overamplified-symbolic',
},
type: {
- headset: "audio-headphones-symbolic",
- speaker: "audio-speakers-symbolic",
- card: "audio-card-symbolic",
+ headset: 'audio-headphones-symbolic',
+ speaker: 'audio-speakers-symbolic',
+ card: 'audio-card-symbolic',
},
- mixer: "mixer-symbolic",
+ mixer: 'mixer-symbolic',
},
powerprofile: {
- balanced: "power-profile-balanced-symbolic",
- "power-saver": "power-profile-power-saver-symbolic",
- performance: "power-profile-performance-symbolic",
+ balanced: 'power-profile-balanced-symbolic',
+ 'power-saver': 'power-profile-power-saver-symbolic',
+ performance: 'power-profile-performance-symbolic',
},
asusctl: {
profile: {
- Balanced: "power-profile-balanced-symbolic",
- Quiet: "power-profile-power-saver-symbolic",
- Performance: "power-profile-performance-symbolic",
+ Balanced: 'power-profile-balanced-symbolic',
+ Quiet: 'power-profile-power-saver-symbolic',
+ Performance: 'power-profile-performance-symbolic',
},
mode: {
- Integrated: "processor-symbolic",
- Hybrid: "controller-symbolic",
+ Integrated: 'processor-symbolic',
+ Hybrid: 'controller-symbolic',
},
},
battery: {
- charging: "battery-flash-symbolic",
- warning: "battery-empty-symbolic",
+ charging: 'battery-flash-symbolic',
+ warning: 'battery-empty-symbolic',
},
bluetooth: {
- enabled: "bluetooth-active-symbolic",
- disabled: "bluetooth-disabled-symbolic",
+ enabled: 'bluetooth-active-symbolic',
+ disabled: 'bluetooth-disabled-symbolic',
},
brightness: {
- indicator: "display-brightness-symbolic",
- keyboard: "keyboard-brightness-symbolic",
- screen: "display-brightness-symbolic",
+ indicator: 'display-brightness-symbolic',
+ keyboard: 'keyboard-brightness-symbolic',
+ screen: 'display-brightness-symbolic',
},
powermenu: {
- sleep: "weather-clear-night-symbolic",
- reboot: "system-reboot-symbolic",
- logout: "system-log-out-symbolic",
- shutdown: "system-shutdown-symbolic",
+ sleep: 'weather-clear-night-symbolic',
+ reboot: 'system-reboot-symbolic',
+ logout: 'system-log-out-symbolic',
+ shutdown: 'system-shutdown-symbolic',
},
recorder: {
- recording: "media-record-symbolic",
+ recording: 'media-record-symbolic',
},
notifications: {
- noisy: "org.gnome.Settings-notifications-symbolic",
- silent: "notifications-disabled-symbolic",
- message: "chat-bubbles-symbolic",
+ noisy: 'org.gnome.Settings-notifications-symbolic',
+ silent: 'notifications-disabled-symbolic',
+ message: 'chat-bubbles-symbolic',
},
trash: {
- full: "user-trash-full-symbolic",
- empty: "user-trash-symbolic",
+ full: 'user-trash-full-symbolic',
+ empty: 'user-trash-symbolic',
},
mpris: {
shuffle: {
- enabled: "media-playlist-shuffle-symbolic",
- disabled: "media-playlist-consecutive-symbolic",
+ enabled: 'media-playlist-shuffle-symbolic',
+ disabled: 'media-playlist-consecutive-symbolic',
},
loop: {
- none: "media-playlist-repeat-symbolic",
- track: "media-playlist-repeat-song-symbolic",
- playlist: "media-playlist-repeat-symbolic",
+ none: 'media-playlist-repeat-symbolic',
+ track: 'media-playlist-repeat-song-symbolic',
+ playlist: 'media-playlist-repeat-symbolic',
},
- playing: "media-playback-pause-symbolic",
- paused: "media-playback-start-symbolic",
- stopped: "media-playback-start-symbolic",
- prev: "media-skip-backward-symbolic",
- next: "media-skip-forward-symbolic",
+ playing: 'media-playback-pause-symbolic',
+ paused: 'media-playback-start-symbolic',
+ stopped: 'media-playback-start-symbolic',
+ prev: 'media-skip-backward-symbolic',
+ next: 'media-skip-forward-symbolic',
},
system: {
- cpu: "org.gnome.SystemMonitor-symbolic",
- ram: "drive-harddisk-solidstate-symbolic",
- temp: "temperature-symbolic",
+ cpu: 'org.gnome.SystemMonitor-symbolic',
+ ram: 'drive-harddisk-solidstate-symbolic',
+ temp: 'temperature-symbolic',
},
color: {
- dark: "dark-mode-symbolic",
- light: "light-mode-symbolic",
+ dark: 'dark-mode-symbolic',
+ light: 'light-mode-symbolic',
},
-}
+};
diff --git a/lib/option.ts b/lib/option.ts
index 1428aff..1c6be5a 100644
--- a/lib/option.ts
+++ b/lib/option.ts
@@ -1,142 +1,147 @@
-import { Variable } from "resource:///com/github/Aylur/ags/variable.js"
+import { isHexColor } from 'globals/variables';
+import { Variable } from 'resource:///com/github/Aylur/ags/variable.js';
+import { MkOptionsResult } from './types/options';
type OptProps = {
- persistent?: boolean
-}
+ persistent?: boolean;
+};
export class Opt extends Variable {
- static { Service.register(this) }
+ static {
+ Service.register(this);
+ }
constructor(initial: T, { persistent = false }: OptProps = {}) {
- super(initial)
- this.initial = initial
- this.persistent = persistent
+ super(initial);
+ this.initial = initial;
+ this.persistent = persistent;
}
- initial: T
- id = ""
- persistent: boolean
- toString() { return `${this.value}` }
- toJSON() { return `opt:${this.value}` }
+ initial: T;
+ id = '';
+ persistent: boolean;
+ toString(): string {
+ return `${this.value}`;
+ }
+ toJSON(): string {
+ return `opt:${this.value}`;
+ }
getValue = (): T => {
- return super.getValue()
+ return super.getValue();
+ };
+ init(cacheFile: string): void {
+ const cacheV = JSON.parse(Utils.readFile(cacheFile) || '{}')[this.id];
+ if (cacheV !== undefined) this.value = cacheV;
+
+ this.connect('changed', () => {
+ const cache = JSON.parse(Utils.readFile(cacheFile) || '{}');
+ cache[this.id] = this.value;
+ Utils.writeFileSync(JSON.stringify(cache, null, 2), cacheFile);
+ });
}
- init(cacheFile: string) {
- const cacheV = JSON.parse(Utils.readFile(cacheFile) || "{}")[this.id]
- if (cacheV !== undefined)
- this.value = cacheV
-
- this.connect("changed", () => {
- const cache = JSON.parse(Utils.readFile(cacheFile) || "{}")
- cache[this.id] = this.value
- Utils.writeFileSync(JSON.stringify(cache, null, 2), cacheFile)
- })
- }
-
- reset() {
- if (this.persistent)
- return;
+ reset(): string | undefined {
+ if (this.persistent) return;
if (JSON.stringify(this.value) !== JSON.stringify(this.initial)) {
- this.value = this.initial
+ this.value = this.initial;
return this.id;
}
}
- doResetColor() {
- if (this.persistent)
- return;
+ doResetColor(): string | undefined {
+ if (this.persistent) return;
- const isColor = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(`${this.value}`);
- if ((JSON.stringify(this.value) !== JSON.stringify(this.initial)) && isColor) {
- this.value = this.initial
- return this.id
+ const isColor = isHexColor(this.value as string);
+ if (JSON.stringify(this.value) !== JSON.stringify(this.initial) && isColor) {
+ this.value = this.initial;
+ return this.id;
}
return;
}
}
-export const opt = (initial: T, opts?: OptProps) => new Opt(initial, opts)
+export const opt = (initial: T, opts?: OptProps): Opt => new Opt(initial, opts);
-function getOptions(object: object, path = ""): Opt[] {
- return Object.keys(object).flatMap(key => {
- const obj: Opt = object[key]
- const id = path ? path + "." + key : key
+const getOptions = (object: Record, path = ''): Opt[] => {
+ return Object.keys(object).flatMap((key) => {
+ const obj = object[key];
+ const id = path ? path + '.' + key : key;
if (obj instanceof Variable) {
- obj.id = id
- return obj
+ const optValue = obj as Opt;
+ optValue.id = id;
+ return optValue;
}
- if (typeof obj === "object")
- return getOptions(obj, id)
+ if (typeof obj === 'object' && obj !== null) {
+ return getOptions(obj as Record, id); // Recursively process nested objects
+ }
- return []
- })
-}
+ return [];
+ });
+};
-export function mkOptions(cacheFile: string, object: T, confFile: string = "config.json") {
- for (const opt of getOptions(object))
- opt.init(cacheFile)
+export function mkOptions(
+ cacheFile: string,
+ object: T,
+ confFile: string = 'config.json',
+): T & MkOptionsResult {
+ for (const opt of getOptions(object as Record)) opt.init(cacheFile);
- Utils.ensureDirectory(cacheFile.split("/").slice(0, -1).join("/"))
+ Utils.ensureDirectory(cacheFile.split('/').slice(0, -1).join('/'));
- const configFile = `${TMP}/${confFile}`
- const values = getOptions(object).reduce((obj, { id, value }) => ({ [id]: value, ...obj }), {})
- Utils.writeFileSync(JSON.stringify(values, null, 2), configFile)
+ const configFile = `${TMP}/${confFile}`;
+ const values = getOptions(object as Record).reduce(
+ (obj, { id, value }) => ({ [id]: value, ...obj }),
+ {},
+ );
+ Utils.writeFileSync(JSON.stringify(values, null, 2), configFile);
Utils.monitorFile(configFile, () => {
- const cache = JSON.parse(Utils.readFile(configFile) || "{}")
- for (const opt of getOptions(object)) {
- if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value))
- opt.value = cache[opt.id]
+ const cache = JSON.parse(Utils.readFile(configFile) || '{}');
+ for (const opt of getOptions(object as Record)) {
+ if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value)) opt.value = cache[opt.id];
}
- })
+ });
function sleep(ms = 0): Promise {
- return new Promise(r => setTimeout(r, ms))
+ return new Promise((r) => setTimeout(r, ms));
}
- async function reset(
- [opt, ...list] = getOptions(object),
+ const reset = async (
+ [opt, ...list] = getOptions(object as Record),
id = opt?.reset(),
- ): Promise> {
- if (!opt)
- return sleep().then(() => [])
+ ): Promise> => {
+ if (!opt) return sleep().then(() => []);
- return id
- ? [id, ...(await sleep(50).then(() => reset(list)))]
- : await sleep().then(() => reset(list))
- }
+ return id ? [id, ...(await sleep(50).then(() => reset(list)))] : await sleep().then(() => reset(list));
+ };
- async function resetTheme(
- [opt, ...list] = getOptions(object),
+ const resetTheme = async (
+ [opt, ...list] = getOptions(object as Record),
id = opt?.doResetColor(),
- ): Promise> {
- if (!opt)
- return sleep().then(() => [])
+ ): Promise> => {
+ if (!opt) return sleep().then(() => []);
return id
? [id, ...(await sleep(50).then(() => resetTheme(list)))]
- : await sleep().then(() => resetTheme(list))
- }
+ : await sleep().then(() => resetTheme(list));
+ };
return Object.assign(object, {
configFile,
- array: () => getOptions(object),
+ array: () => getOptions(object as Record),
async reset() {
- return (await reset()).join("\n")
+ return (await reset()).join('\n');
},
async resetTheme() {
- return (await resetTheme()).join("\n")
+ return (await resetTheme()).join('\n');
},
handler(deps: string[], callback: () => void) {
- for (const opt of getOptions(object)) {
- if (deps.some(i => opt.id.startsWith(i)))
- opt.connect("changed", callback)
+ for (const opt of getOptions(object as Record)) {
+ if (deps.some((i) => opt.id.startsWith(i))) opt.connect('changed', callback);
}
},
- })
+ });
}
-
diff --git a/lib/session.ts b/lib/session.ts
index 3c828c3..595b366 100644
--- a/lib/session.ts
+++ b/lib/session.ts
@@ -1,16 +1,16 @@
-import GLib from "gi://GLib?version=2.0"
+import GLib from 'gi://GLib?version=2.0';
declare global {
- const OPTIONS: string
- const TMP: string
- const USER: string
+ const OPTIONS: string;
+ const TMP: string;
+ const USER: string;
}
Object.assign(globalThis, {
OPTIONS: `${GLib.get_user_cache_dir()}/ags/hyprpanel/options.json`,
TMP: `${GLib.get_tmp_dir()}/ags/hyprpanel`,
USER: GLib.get_user_name(),
-})
+});
-Utils.ensureDirectory(TMP)
-App.addIcons(`${App.configDir}/assets`)
+Utils.ensureDirectory(TMP);
+App.addIcons(`${App.configDir}/assets`);
diff --git a/lib/shared/media.ts b/lib/shared/media.ts
index 733fdcf..23e0c6f 100644
--- a/lib/shared/media.ts
+++ b/lib/shared/media.ts
@@ -1,5 +1,5 @@
-import { MprisPlayer } from "types/service/mpris";
-const mpris = await Service.import("mpris");
+import { MprisPlayer } from 'types/service/mpris';
+const mpris = await Service.import('mpris');
export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]): MprisPlayer => {
const statusOrder = {
@@ -12,18 +12,12 @@ export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]):
return mpris.players[0];
}
- const isPlaying = mpris.players.some(
- (p) => p["play-back-status"] === "Playing",
- );
+ const isPlaying = mpris.players.some((p: MprisPlayer) => p.play_back_status === 'Playing');
- const playerStillExists = mpris.players.some(
- (p) => activePlayer["bus-name"] === p["bus-name"],
- );
+ const playerStillExists = mpris.players.some((p) => activePlayer.bus_name === p.bus_name);
const nextPlayerUp = mpris.players.sort(
- (a, b) =>
- statusOrder[a["play-back-status"]] -
- statusOrder[b["play-back-status"]],
+ (a: MprisPlayer, b: MprisPlayer) => statusOrder[a.play_back_status] - statusOrder[b.play_back_status],
)[0];
if (isPlaying || !playerStillExists) {
@@ -31,4 +25,4 @@ export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]):
}
return activePlayer;
-}
+};
diff --git a/lib/shared/notifications.ts b/lib/shared/notifications.ts
new file mode 100644
index 0000000..f772c69
--- /dev/null
+++ b/lib/shared/notifications.ts
@@ -0,0 +1,12 @@
+import { Notification } from 'types/service/notifications';
+
+export const filterNotifications = (notifications: Notification[], filter: string[]): Notification[] => {
+ const notifFilter = new Set(filter.map((name: string) => name.toLowerCase().replace(/\s+/g, '_')));
+
+ const filteredNotifications = notifications.filter((notif: Notification) => {
+ const normalizedAppName = notif.app_name.toLowerCase().replace(/\s+/g, '_');
+ return !notifFilter.has(normalizedAppName);
+ });
+
+ return filteredNotifications;
+};
diff --git a/lib/types/audio.d.ts b/lib/types/audio.d.ts
new file mode 100644
index 0000000..9332431
--- /dev/null
+++ b/lib/types/audio.d.ts
@@ -0,0 +1,5 @@
+export type InputDevices = Button, Attribute>, Attribute>, Attribute>[];
+
+type DummyDevices = Button, Attribute>, Attribute>, Attribute>[];
+type RealPlaybackDevices = Button, Attribute>, Attribute>, Attribute>[];
+export type PlaybackDevices = DummyDevices | RealPlaybackDevices;
diff --git a/lib/types/bar.d.ts b/lib/types/bar.d.ts
index 907a728..01176ae 100644
--- a/lib/types/bar.d.ts
+++ b/lib/types/bar.d.ts
@@ -1,43 +1,45 @@
-import { Binding, Connectable } from "types/service"
-import { Variable } from "types/variable"
-import Box from "types/widgets/box";
-import Label from "types/widgets/label";
-import { Widget as WidgetType } from "types/widgets/widget"
+import { Binding, Connectable } from 'types/service';
+import { Variable } from 'types/variable';
+import Box from 'types/widgets/box';
+import Button from 'types/widgets/button';
+import Label from 'types/widgets/label';
+import { Attribute, Child } from './widget';
-export type Child = {
+export type BarBoxChild = {
component: Box;
isVisible?: boolean;
isVis?: Variable;
boxClass: string;
- props: ButtonProps;
-};
+} & ButtonProps;
+
+export type SelfButton = Button;
export type BoxHook = (self: Box) => void;
export type LabelHook = (self: Label) => void;
export type Module = {
- icon?: string | Binding,
- textIcon?: string | Binding,
- label?: string | Binding,
- labelHook?: LabelHook,
- boundLabel?: string,
- tooltipText?: string | Binding,
- boxClass: string,
- props?: ButtonProps,
- showLabel?: boolean,
- showLabelBinding?: Binding,
- hook?: BoxHook,
- connection?: Binding
-}
+ icon?: string | Binding;
+ textIcon?: string | Binding;
+ label?: string | Binding;
+ labelHook?: LabelHook;
+ boundLabel?: string;
+ tooltipText?: string | Binding;
+ boxClass: string;
+ props?: ButtonProps;
+ showLabel?: boolean;
+ showLabelBinding?: Binding;
+ hook?: BoxHook;
+ connection?: Binding;
+};
-export type ResourceLabelType = "used/total" | "used" | "percentage" | "free";
+export type ResourceLabelType = 'used/total' | 'used' | 'percentage' | 'free';
-export type StorageIcon = "" | "" | "" | "" | "" | "";
+export type StorageIcon = '' | '' | '' | '' | '' | '';
-export type NetstatIcon = "" | "" | "" | "" | "" | "" | "" | "" | "";
-export type NetstatLabelType = "full" | "in" | "out";
-export type RateUnit = "GiB" | "MiB" | "KiB" | "auto";
+export type NetstatIcon = '' | '' | '' | '' | '' | '' | '' | '' | '';
+export type NetstatLabelType = 'full' | 'in' | 'out';
+export type RateUnit = 'GiB' | 'MiB' | 'KiB' | 'auto';
-export type UpdatesIcon = "" | "" | "" | "" | "" | "" | "" | "" | "";
+export type UpdatesIcon = '' | '' | '' | '' | '' | '' | '' | '' | '';
-export type PowerIcon = "" | "" | "" | "" | "" | "";
+export type PowerIcon = '' | '' | '' | '' | '' | '';
diff --git a/lib/types/customModules/generic.d.ts b/lib/types/customModules/generic.d.ts
index 8741fd5..839e04a 100644
--- a/lib/types/customModules/generic.d.ts
+++ b/lib/types/customModules/generic.d.ts
@@ -1,6 +1,13 @@
-export type GenericResourceData = {
+export type GenericFunction = (...args: P) => T;
+
+export type GenericResourceMetrics = {
total: number;
used: number;
- free: number;
percentage: number;
-}
+};
+
+type GenericResourceData = ResourceUsage & {
+ free: number;
+};
+
+export type Postfix = 'TiB' | 'GiB' | 'MiB' | 'KiB' | 'B';
diff --git a/lib/types/customModules/kbLayout.d.ts b/lib/types/customModules/kbLayout.d.ts
index aee1464..93ecea4 100644
--- a/lib/types/customModules/kbLayout.d.ts
+++ b/lib/types/customModules/kbLayout.d.ts
@@ -1,5 +1,7 @@
-export type KbLabelType = "layout" | "code";
-export type KbIcon = "" | "" | "" | "" | "";
+import { layoutMap } from 'customModules/kblayout/layouts';
+
+export type KbLabelType = 'layout' | 'code';
+export type KbIcon = '' | '' | '' | '' | '';
export type HyprctlKeyboard = {
address: string;
@@ -22,7 +24,10 @@ export type HyprctlMouse = {
export type HyprctlDeviceLayout = {
mice: HyprctlMouse[];
keyboards: HyprctlKeyboard[];
- tablets: any[];
- touch: any[];
- switches: any[];
+ tablets: unknown[];
+ touch: unknown[];
+ switches: unknown[];
};
+
+export type LayoutKeys = keyof typeof layoutMap;
+export type LayoutValues = (typeof layoutMap)[LayoutKeys];
diff --git a/lib/types/customModules/network.d.ts b/lib/types/customModules/network.d.ts
index 77a02c6..dbef13f 100644
--- a/lib/types/customModules/network.d.ts
+++ b/lib/types/customModules/network.d.ts
@@ -1,5 +1,4 @@
export type NetworkResourceData = {
in: string;
out: string;
-}
-
+};
diff --git a/lib/types/customModules/utils.d.ts b/lib/types/customModules/utils.d.ts
index e69de29..9764bc8 100644
--- a/lib/types/customModules/utils.d.ts
+++ b/lib/types/customModules/utils.d.ts
@@ -0,0 +1,9 @@
+import { Binding } from 'lib/utils';
+
+export type InputHandlerEvents = {
+ onPrimaryClick?: Binding;
+ onSecondaryClick?: Binding;
+ onMiddleClick?: Binding;
+ onScrollUp?: Binding;
+ onScrollDown?: Binding;
+};
diff --git a/lib/types/defaults/bar.ts b/lib/types/defaults/bar.ts
index 37a3dc6..78966c4 100644
--- a/lib/types/defaults/bar.ts
+++ b/lib/types/defaults/bar.ts
@@ -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'];
diff --git a/lib/types/defaults/netstat.ts b/lib/types/defaults/netstat.ts
index 2184e0b..083344b 100644
--- a/lib/types/defaults/netstat.ts
+++ b/lib/types/defaults/netstat.ts
@@ -1,10 +1,10 @@
-import { RateUnit } from "../bar";
-import { NetworkResourceData } from "../customModules/network";
+import { RateUnit } from '../bar';
+import { NetworkResourceData } from '../customModules/network';
export const GET_DEFAULT_NETSTAT_DATA = (dataType: RateUnit): NetworkResourceData => {
if (dataType === 'auto') {
- return { in: `0 Kib/s`, out: `0 Kib/s` }
+ return { in: `0 Kib/s`, out: `0 Kib/s` };
}
- return { in: `0 ${dataType}/s`, out: `0 ${dataType}/s` }
+ return { in: `0 ${dataType}/s`, out: `0 ${dataType}/s` };
};
diff --git a/lib/types/defaults/options.ts b/lib/types/defaults/options.ts
index 1e390c9..11b7347 100644
--- a/lib/types/defaults/options.ts
+++ b/lib/types/defaults/options.ts
@@ -1,60 +1,60 @@
export const defaultColorMap = {
- "rosewater": "#f5e0dc",
- "flamingo": "#f2cdcd",
- "pink": "#f5c2e7",
- "mauve": "#cba6f7",
- "red": "#f38ba8",
- "maroon": "#eba0ac",
- "peach": "#fab387",
- "yellow": "#f9e2af",
- "green": "#a6e3a1",
- "teal": "#94e2d5",
- "sky": "#89dceb",
- "sapphire": "#74c7ec",
- "blue": "#89b4fa",
- "lavender": "#b4befe",
- "text": "#cdd6f4",
- "subtext1": "#bac2de",
- "subtext2": "#a6adc8",
- "overlay2": "#9399b2",
- "overlay1": "#7f849c",
- "overlay0": "#6c7086",
- "surface2": "#585b70",
- "surface1": "#45475a",
- "surface0": "#313244",
- "base2": "#242438",
- "base": "#1e1e2e",
- "mantle": "#181825",
- "crust": "#11111b",
- "surface1_2": "#454759",
- "text2": "#cdd6f3",
- "pink2": "#f5c2e6",
- "red2": "#f38ba7",
- "peach2": "#fab386",
- "mantle2": "#181824",
- "surface0_2": "#313243",
- "surface2_2": "#585b69",
- "overlay1_2": "#7f849b",
- "lavender2": "#b4befd",
- "mauve2": "#cba6f6",
- "green2": "#a6e3a0",
- "sky2": "#89dcea",
- "teal2": "#94e2d4",
- "yellow2": "#f9e2ad",
- "maroon2": "#eba0ab",
- "crust2": "#11111a",
- "pink3": "#f5c2e8",
- "red3": "#f38ba9",
- "mantle3": "#181826",
- "surface0_3": "#313245",
- "surface2_3": "#585b71",
- "overlay1_3": "#7f849d",
- "lavender3": "#b4beff",
- "mauve3": "#cba6f8",
- "green3": "#a6e3a2",
- "sky3": "#89dcec",
- "teal3": "#94e2d6",
- "yellow3": "#f9e2ae",
- "maroon3": "#eba0ad",
- "crust3": "#11111c",
-};
+ rosewater: '#f5e0dc',
+ flamingo: '#f2cdcd',
+ pink: '#f5c2e7',
+ mauve: '#cba6f7',
+ red: '#f38ba8',
+ maroon: '#eba0ac',
+ peach: '#fab387',
+ yellow: '#f9e2af',
+ green: '#a6e3a1',
+ teal: '#94e2d5',
+ sky: '#89dceb',
+ sapphire: '#74c7ec',
+ blue: '#89b4fa',
+ lavender: '#b4befe',
+ text: '#cdd6f4',
+ subtext1: '#bac2de',
+ subtext2: '#a6adc8',
+ overlay2: '#9399b2',
+ overlay1: '#7f849c',
+ overlay0: '#6c7086',
+ surface2: '#585b70',
+ surface1: '#45475a',
+ surface0: '#313244',
+ base2: '#242438',
+ base: '#1e1e2e',
+ mantle: '#181825',
+ crust: '#11111b',
+ surface1_2: '#454759',
+ text2: '#cdd6f3',
+ pink2: '#f5c2e6',
+ red2: '#f38ba7',
+ peach2: '#fab386',
+ mantle2: '#181824',
+ surface0_2: '#313243',
+ surface2_2: '#585b69',
+ overlay1_2: '#7f849b',
+ lavender2: '#b4befd',
+ mauve2: '#cba6f6',
+ green2: '#a6e3a0',
+ sky2: '#89dcea',
+ teal2: '#94e2d4',
+ yellow2: '#f9e2ad',
+ maroon2: '#eba0ab',
+ crust2: '#11111a',
+ pink3: '#f5c2e8',
+ red3: '#f38ba9',
+ mantle3: '#181826',
+ surface0_3: '#313245',
+ surface2_3: '#585b71',
+ overlay1_3: '#7f849d',
+ lavender3: '#b4beff',
+ mauve3: '#cba6f8',
+ green3: '#a6e3a2',
+ sky3: '#89dcec',
+ teal3: '#94e2d6',
+ yellow3: '#f9e2ae',
+ maroon3: '#eba0ad',
+ crust3: '#11111c',
+} as const;
diff --git a/lib/types/defaults/weather.ts b/lib/types/defaults/weather.ts
index ed4443e..cde95e3 100644
--- a/lib/types/defaults/weather.ts
+++ b/lib/types/defaults/weather.ts
@@ -1,1053 +1,1053 @@
export const DEFAULT_WEATHER = {
- "location": {
- "name": "Tahiti",
- "region": "Somewhere",
- "country": "United States of America",
- "lat": 0,
- "lon": 0,
- "tz_id": "Tahiti",
- "localtime_epoch": 1721981457,
- "localtime": "2024-07-26 1:10"
+ location: {
+ name: 'Tahiti',
+ region: 'Somewhere',
+ country: 'United States of America',
+ lat: 0,
+ lon: 0,
+ tz_id: 'Tahiti',
+ localtime_epoch: 1721981457,
+ localtime: '2024-07-26 1:10',
},
- "current": {
- "last_updated_epoch": 1721980800,
- "last_updated": "2024-07-26 01:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ current: {
+ last_updated_epoch: 1721980800,
+ last_updated: '2024-07-26 01:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "NW",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0.0,
- "precip_in": 0.0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "uv": 0,
- "gust_mph": 0,
- "gust_kph": 0,
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'NW',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0.0,
+ precip_in: 0.0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ uv: 0,
+ gust_mph: 0,
+ gust_kph: 0,
},
- "forecast": {
- "forecastday": [
+ forecast: {
+ forecastday: [
{
- "date": "2024-07-26",
- "date_epoch": 1721952000,
- "day": {
- "maxtemp_c": 0,
- "maxtemp_f": 0,
- "mintemp_c": 0,
- "mintemp_f": 0,
- "avgtemp_c": 0,
- "avgtemp_f": 0,
- "maxwind_mph": 0,
- "maxwind_kph": 0,
- "totalprecip_mm": 0,
- "totalprecip_in": 0,
- "totalsnow_cm": 0,
- "avgvis_km": 0,
- "avgvis_miles": 0,
- "avghumidity": 0,
- "daily_will_it_rain": 0,
- "daily_chance_of_rain": 0,
- "daily_will_it_snow": 0,
- "daily_chance_of_snow": 0,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ date: '2024-07-26',
+ date_epoch: 1721952000,
+ day: {
+ maxtemp_c: 0,
+ maxtemp_f: 0,
+ mintemp_c: 0,
+ mintemp_f: 0,
+ avgtemp_c: 0,
+ avgtemp_f: 0,
+ maxwind_mph: 0,
+ maxwind_kph: 0,
+ totalprecip_mm: 0,
+ totalprecip_in: 0,
+ totalsnow_cm: 0,
+ avgvis_km: 0,
+ avgvis_miles: 0,
+ avghumidity: 0,
+ daily_will_it_rain: 0,
+ daily_chance_of_rain: 0,
+ daily_will_it_snow: 0,
+ daily_chance_of_snow: 0,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "uv": 0,
+ uv: 0,
},
- "astro": {
- "sunrise": "06:01 AM",
- "sunset": "08:10 PM",
- "moonrise": "11:32 PM",
- "moonset": "12:01 PM",
- "moon_phase": "Waning Gibbous",
- "moon_illumination": 0,
- "is_moon_up": 0,
- "is_sun_up": 0,
+ astro: {
+ sunrise: '06:01 AM',
+ sunset: '08:10 PM',
+ moonrise: '11:32 PM',
+ moonset: '12:01 PM',
+ moon_phase: 'Waning Gibbous',
+ moon_illumination: 0,
+ is_moon_up: 0,
+ is_sun_up: 0,
},
- "hour": [
+ hour: [
{
- "time_epoch": 1721977200,
- "time": "2024-07-26 00:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1721977200,
+ time: '2024-07-26 00:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1721980800,
- "time": "2024-07-26 01:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1721980800,
+ time: '2024-07-26 01:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1721984400,
- "time": "2024-07-26 02:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1721984400,
+ time: '2024-07-26 02:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1721988000,
- "time": "2024-07-26 03:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1721988000,
+ time: '2024-07-26 03:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1721991600,
- "time": "2024-07-26 04:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1721991600,
+ time: '2024-07-26 04:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1721995200,
- "time": "2024-07-26 05:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1721995200,
+ time: '2024-07-26 05:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1721998800,
- "time": "2024-07-26 06:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1721998800,
+ time: '2024-07-26 06:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1722002400,
- "time": "2024-07-26 07:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722002400,
+ time: '2024-07-26 07:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 7.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 7.0,
},
{
- "time_epoch": 1722006000,
- "time": "2024-07-26 08:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722006000,
+ time: '2024-07-26 08:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 7.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 7.0,
},
{
- "time_epoch": 1722009600,
- "time": "2024-07-26 09:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722009600,
+ time: '2024-07-26 09:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 8.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 8.0,
},
{
- "time_epoch": 1722013200,
- "time": "2024-07-26 10:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722013200,
+ time: '2024-07-26 10:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 8.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 8.0,
},
{
- "time_epoch": 1722016800,
- "time": "2024-07-26 11:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722016800,
+ time: '2024-07-26 11:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 9.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 9.0,
},
{
- "time_epoch": 1722020400,
- "time": "2024-07-26 12:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722020400,
+ time: '2024-07-26 12:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 9.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 9.0,
},
{
- "time_epoch": 1722024000,
- "time": "2024-07-26 13:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722024000,
+ time: '2024-07-26 13:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 9.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 9.0,
},
{
- "time_epoch": 1722027600,
- "time": "2024-07-26 14:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722027600,
+ time: '2024-07-26 14:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 10.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 10.0,
},
{
- "time_epoch": 1722031200,
- "time": "2024-07-26 15:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722031200,
+ time: '2024-07-26 15:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 10.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 10.0,
},
{
- "time_epoch": 1722034800,
- "time": "2024-07-26 16:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722034800,
+ time: '2024-07-26 16:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 10.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 10.0,
},
{
- "time_epoch": 1722038400,
- "time": "2024-07-26 17:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722038400,
+ time: '2024-07-26 17:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 10.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 10.0,
},
{
- "time_epoch": 1722042000,
- "time": "2024-07-26 18:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722042000,
+ time: '2024-07-26 18:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 9.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 9.0,
},
{
- "time_epoch": 1722045600,
- "time": "2024-07-26 19:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722045600,
+ time: '2024-07-26 19:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 9.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 9.0,
},
{
- "time_epoch": 1722049200,
- "time": "2024-07-26 20:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 1,
- "condition": {
- "text": "Sunny",
- "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
- "code": 1000
+ time_epoch: 1722049200,
+ time: '2024-07-26 20:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 1,
+ condition: {
+ text: 'Sunny',
+ icon: '//cdn.weatherapi.com/weather/64x64/day/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 8.0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 8.0,
},
{
- "time_epoch": 1722052800,
- "time": "2024-07-26 21:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1722052800,
+ time: '2024-07-26 21:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1722056400,
- "time": "2024-07-26 22:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1722056400,
+ time: '2024-07-26 22:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
},
{
- "time_epoch": 1722060000,
- "time": "2024-07-26 23:00",
- "temp_c": 0,
- "temp_f": 0,
- "is_day": 0,
- "condition": {
- "text": "Clear ",
- "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
- "code": 1000
+ time_epoch: 1722060000,
+ time: '2024-07-26 23:00',
+ temp_c: 0,
+ temp_f: 0,
+ is_day: 0,
+ condition: {
+ text: 'Clear ',
+ icon: '//cdn.weatherapi.com/weather/64x64/night/113.png',
+ code: 1000,
},
- "wind_mph": 0,
- "wind_kph": 0,
- "wind_degree": 0,
- "wind_dir": "N",
- "pressure_mb": 0,
- "pressure_in": 0,
- "precip_mm": 0,
- "precip_in": 0,
- "snow_cm": 0,
- "humidity": 0,
- "cloud": 0,
- "feelslike_c": 0,
- "feelslike_f": 0,
- "windchill_c": 0,
- "windchill_f": 0,
- "heatindex_c": 0,
- "heatindex_f": 0,
- "dewpoint_c": 0,
- "dewpoint_f": 0,
- "will_it_rain": 0,
- "chance_of_rain": 0,
- "will_it_snow": 0,
- "chance_of_snow": 0,
- "vis_km": 0,
- "vis_miles": 0,
- "gust_mph": 0,
- "gust_kph": 0,
- "uv": 0
- }
- ]
- }
- ]
- }
-}
+ wind_mph: 0,
+ wind_kph: 0,
+ wind_degree: 0,
+ wind_dir: 'N',
+ pressure_mb: 0,
+ pressure_in: 0,
+ precip_mm: 0,
+ precip_in: 0,
+ snow_cm: 0,
+ humidity: 0,
+ cloud: 0,
+ feelslike_c: 0,
+ feelslike_f: 0,
+ windchill_c: 0,
+ windchill_f: 0,
+ heatindex_c: 0,
+ heatindex_f: 0,
+ dewpoint_c: 0,
+ dewpoint_f: 0,
+ will_it_rain: 0,
+ chance_of_rain: 0,
+ will_it_snow: 0,
+ chance_of_snow: 0,
+ vis_km: 0,
+ vis_miles: 0,
+ gust_mph: 0,
+ gust_kph: 0,
+ uv: 0,
+ },
+ ],
+ },
+ ],
+ },
+};
diff --git a/lib/types/dropdownmenu.d.ts b/lib/types/dropdownmenu.d.ts
new file mode 100644
index 0000000..1349b3d
--- /dev/null
+++ b/lib/types/dropdownmenu.d.ts
@@ -0,0 +1,11 @@
+import { WindowProps } from 'types/widgets/window';
+import { GtkWidget, Transition } from './widget';
+
+export type DropdownMenuProps = {
+ name: string;
+ child: GtkWidget;
+ layout?: string;
+ transition?: Transition;
+ exclusivity?: Exclusivity;
+ fixed?: boolean;
+} & WindowProps;
diff --git a/lib/types/filechooser.d.ts b/lib/types/filechooser.d.ts
new file mode 100644
index 0000000..8bb9d8f
--- /dev/null
+++ b/lib/types/filechooser.d.ts
@@ -0,0 +1,3 @@
+export type Config = {
+ [key: string]: string | number | boolean | object;
+};
diff --git a/lib/types/gpustat.d.ts b/lib/types/gpustat.d.ts
index ede3378..49dc75d 100644
--- a/lib/types/gpustat.d.ts
+++ b/lib/types/gpustat.d.ts
@@ -12,14 +12,14 @@ export type GPU_Stat = {
index: number;
uuid: string;
name: string;
- "temperature.gpu": number;
- "fan.speed": number;
- "utilization.gpu": number;
- "utilization.enc": number;
- "utilization.dec": number;
- "power.draw": number;
- "enforced.power.limit": number;
- "memory.used": number;
- "memory.total": number;
+ 'temperature.gpu': number;
+ 'fan.speed': number;
+ 'utilization.gpu': number;
+ 'utilization.enc': number;
+ 'utilization.dec': number;
+ 'power.draw': number;
+ 'enforced.power.limit': number;
+ 'memory.used': number;
+ 'memory.total': number;
processes: Process[];
};
diff --git a/lib/types/mpris.d.ts b/lib/types/mpris.d.ts
new file mode 100644
index 0000000..5450e80
--- /dev/null
+++ b/lib/types/mpris.d.ts
@@ -0,0 +1,2 @@
+export type LoopStatus = 'none' | 'track' | 'playlist';
+export type PlaybackStatus = 'playing' | 'paused' | 'stopped';
diff --git a/lib/types/network.d.ts b/lib/types/network.d.ts
index 63c8804..58dcdec 100644
--- a/lib/types/network.d.ts
+++ b/lib/types/network.d.ts
@@ -1,3 +1,5 @@
+import { WIFI_STATUS_MAP } from 'globals/network';
+
export type AccessPoint = {
bssid: string | null;
address: string | null;
@@ -7,4 +9,8 @@ export type AccessPoint = {
strength: number;
frequency: number;
iconName: string | undefined;
-}
+};
+
+export type WifiStatus = keyof typeof WIFI_STATUS_MAP;
+
+export type WifiIcon = '' | '' | '' | '' | '' | '' | '' | '' | '' | '' | '';
diff --git a/lib/types/notification.d.ts b/lib/types/notification.d.ts
index 60f8dea..027f195 100644
--- a/lib/types/notification.d.ts
+++ b/lib/types/notification.d.ts
@@ -1,3 +1,5 @@
+import icons from 'modules/icons/index';
+
export interface NotificationArgs {
appName?: string;
body?: string;
@@ -9,3 +11,5 @@ export interface NotificationArgs {
timeout?: number;
transient?: boolean;
}
+
+export type NotificationIcon = keyof typeof icons.notifications;
diff --git a/lib/types/options.d.ts b/lib/types/options.d.ts
index 9c6330e..6c913f1 100644
--- a/lib/types/options.d.ts
+++ b/lib/types/options.d.ts
@@ -1,119 +1,215 @@
-import { Opt } from "lib/option";
-import { Variable } from "types/variable";
+import { Opt } from 'lib/option';
+import { Variable } from 'types/variable';
+import { defaultColorMap } from './defaults/options';
-export type Unit = "imperial" | "metric";
-export type PowerOptions = "sleep" | "reboot" | "logout" | "shutdown";
-export type NotificationAnchor = "top" | "top right" | "top left" | "bottom" | "bottom right" | "bottom left" | "left" | "right";
-export type OSDAnchor = "top left" | "top" | "top right" | "right" | "bottom right" | "bottom" | "bottom left" | "left";
-export type BarButtonStyles = "default" | "split" | "wave" | "wave2";
+export type MkOptionsResult = {
+ configFile: string;
+ array: () => Opt[];
+ reset: () => Promise;
+ resetTheme: () => Promise;
+ handler: (deps: string[], callback: () => void) => void;
+};
+
+export type RecursiveOptionsObject = {
+ [key: string]: RecursiveOptionsObject | Opt | Opt;
+};
+
+export type BarLocation = 'top' | 'bottom';
+
+export type Unit = 'imperial' | 'metric';
+export type PowerOptions = 'sleep' | 'reboot' | 'logout' | 'shutdown';
+export type NotificationAnchor =
+ | 'top'
+ | 'top right'
+ | 'top left'
+ | 'bottom'
+ | 'bottom right'
+ | 'bottom left'
+ | 'left'
+ | 'right';
+export type OSDAnchor = 'top left' | 'top' | 'top right' | 'right' | 'bottom right' | 'bottom' | 'bottom left' | 'left';
+export type BarButtonStyles = 'default' | 'split' | 'wave' | 'wave2';
export type ThemeExportData = {
- filePath: string,
- themeOnly: boolean
-}
+ filePath: string;
+ themeOnly: boolean;
+};
export type RowProps = {
- opt: Opt
- title: string
- note?: string
+ opt: Opt;
+ title: string;
+ note?: string;
type?:
- | "number"
- | "color"
- | "float"
- | "object"
- | "string"
- | "enum"
- | "boolean"
- | "img"
- | "wallpaper"
- | "export"
- | "import"
- | "config_import"
- | "font"
- enums?: string[]
- max?: number
- min?: number
- disabledBinding?: Variable
- exportData?: ThemeExportData
- subtitle?: string | VarType | Opt,
- subtitleLink?: string,
- dependencies?: string[],
- increment?: number
-}
+ | 'number'
+ | 'color'
+ | 'float'
+ | 'object'
+ | 'string'
+ | 'enum'
+ | 'boolean'
+ | 'img'
+ | 'wallpaper'
+ | 'export'
+ | 'import'
+ | 'config_import'
+ | 'font';
+ enums?: T[];
+ max?: number;
+ min?: number;
+ disabledBinding?: Variable;
+ exportData?: ThemeExportData;
+ subtitle?: string | VarType | Opt;
+ subtitleLink?: string;
+ dependencies?: string[];
+ increment?: number;
+};
-export type OSDOrientation = "horizontal" | "vertical";
+export type OSDOrientation = 'horizontal' | 'vertical';
export type HexColor = `#${string}`;
+export type WindowLayer = 'top' | 'bottom' | 'overlay' | 'background';
+
+export type ActiveWsIndicator = 'underline' | 'highlight' | 'color';
+
export type MatugenColors = {
- "background": HexColor,
- "error": HexColor,
- "error_container": HexColor,
- "inverse_on_surface": HexColor,
- "inverse_primary": HexColor,
- "inverse_surface": HexColor,
- "on_background": HexColor,
- "on_error": HexColor,
- "on_error_container": HexColor,
- "on_primary": HexColor,
- "on_primary_container": HexColor,
- "on_primary_fixed": HexColor,
- "on_primary_fixed_variant": HexColor,
- "on_secondary": HexColor,
- "on_secondary_container": HexColor,
- "on_secondary_fixed": HexColor,
- "on_secondary_fixed_variant": HexColor,
- "on_surface": HexColor,
- "on_surface_variant": HexColor,
- "on_tertiary": HexColor,
- "on_tertiary_container": HexColor,
- "on_tertiary_fixed": HexColor,
- "on_tertiary_fixed_variant": HexColor,
- "outline": HexColor,
- "outline_variant": HexColor,
- "primary": HexColor,
- "primary_container": HexColor,
- "primary_fixed": HexColor,
- "primary_fixed_dim": HexColor,
- "scrim": HexColor,
- "secondary": HexColor,
- "secondary_container": HexColor,
- "secondary_fixed": HexColor,
- "secondary_fixed_dim": HexColor,
- "shadow": HexColor,
- "surface": HexColor,
- "surface_bright": HexColor,
- "surface_container": HexColor,
- "surface_container_high": HexColor,
- "surface_container_highest": HexColor,
- "surface_container_low": HexColor,
- "surface_container_lowest": HexColor,
- "surface_dim": HexColor,
- "surface_variant": HexColor,
- "tertiary": HexColor,
- "tertiary_container": HexColor,
- "tertiary_fixed": HexColor,
- "tertiary_fixed_dim": HexColor
-}
+ background: HexColor;
+ error: HexColor;
+ error_container: HexColor;
+ inverse_on_surface: HexColor;
+ inverse_primary: HexColor;
+ inverse_surface: HexColor;
+ on_background: HexColor;
+ on_error: HexColor;
+ on_error_container: HexColor;
+ on_primary: HexColor;
+ on_primary_container: HexColor;
+ on_primary_fixed: HexColor;
+ on_primary_fixed_variant: HexColor;
+ on_secondary: HexColor;
+ on_secondary_container: HexColor;
+ on_secondary_fixed: HexColor;
+ on_secondary_fixed_variant: HexColor;
+ on_surface: HexColor;
+ on_surface_variant: HexColor;
+ on_tertiary: HexColor;
+ on_tertiary_container: HexColor;
+ on_tertiary_fixed: HexColor;
+ on_tertiary_fixed_variant: HexColor;
+ outline: HexColor;
+ outline_variant: HexColor;
+ primary: HexColor;
+ primary_container: HexColor;
+ primary_fixed: HexColor;
+ primary_fixed_dim: HexColor;
+ scrim: HexColor;
+ secondary: HexColor;
+ secondary_container: HexColor;
+ secondary_fixed: HexColor;
+ secondary_fixed_dim: HexColor;
+ shadow: HexColor;
+ surface: HexColor;
+ surface_bright: HexColor;
+ surface_container: HexColor;
+ surface_container_high: HexColor;
+ surface_container_highest: HexColor;
+ surface_container_low: HexColor;
+ surface_container_lowest: HexColor;
+ surface_dim: HexColor;
+ surface_variant: HexColor;
+ tertiary: HexColor;
+ tertiary_container: HexColor;
+ tertiary_fixed: HexColor;
+ tertiary_fixed_dim: HexColor;
+};
-type MatugenScheme =
- | "content"
- | "expressive"
- | "fidelity"
- | "fruit-salad"
- | "monochrome"
- | "neutral"
- | "rainbow"
- | "tonal-spot";
+export type MatugenVariation = {
+ rosewater: HexColor;
+ flamingo: HexColor;
+ pink: HexColor;
+ mauve: HexColor;
+ red: HexColor;
+ maroon: HexColor;
+ peach: HexColor;
+ yellow: HexColor;
+ green: HexColor;
+ teal: HexColor;
+ sky: HexColor;
+ sapphire: HexColor;
+ blue: HexColor;
+ lavender: HexColor;
+ text: HexColor;
+ subtext1: HexColor;
+ subtext2: HexColor;
+ overlay2: HexColor;
+ overlay1: HexColor;
+ overlay0: HexColor;
+ surface2: HexColor;
+ surface1: HexColor;
+ surface0: HexColor;
+ base2: HexColor;
+ base: HexColor;
+ mantle: HexColor;
+ crust: HexColor;
+ notifications_closer: HexColor;
+ notifications_background: HexColor;
+ dashboard_btn_text: HexColor;
+ red2: HexColor;
+ peach2: HexColor;
+ pink2: HexColor;
+ mantle2: HexColor;
+ surface1_2: HexColor;
+ surface0_2: HexColor;
+ overlay1_2: HexColor;
+ text2: HexColor;
+ lavender2: HexColor;
+ crust2: HexColor;
+ maroon2: HexColor;
+ mauve2: HexColor;
+ green2: HexColor;
+ surface2_2: HexColor;
+ sky2: HexColor;
+ teal2: HexColor;
+ yellow2: HexColor;
+ pink3: HexColor;
+ red3: HexColor;
+ mantle3: HexColor;
+ surface0_3: HexColor;
+ surface2_3: HexColor;
+ overlay1_3: HexColor;
+ lavender3: HexColor;
+ mauve3: HexColor;
+ green3: HexColor;
+ sky3: HexColor;
+ teal3: HexColor;
+ yellow3: HexColor;
+ maroon3: HexColor;
+ crust3: HexColor;
+ notifications_closer?: HexColor;
+ notifications_background?: HexColor;
+ dashboard_btn_text?: HexColor;
+};
+export type MatugenScheme =
+ | 'content'
+ | 'expressive'
+ | 'fidelity'
+ | 'fruit-salad'
+ | 'monochrome'
+ | 'neutral'
+ | 'rainbow'
+ | 'tonal-spot';
-type MatugenVariation =
- | "standard_1"
- | "standard_2"
- | "standard_3"
- | "monochrome_1"
- | "monochrome_2"
- | "monochrome_3"
- | "vivid_1"
- | "vivid_2"
- | "vivid_3"
+export type MatugenVariations =
+ | 'standard_1'
+ | 'standard_2'
+ | 'standard_3'
+ | 'monochrome_1'
+ | 'monochrome_2'
+ | 'monochrome_3'
+ | 'vivid_1'
+ | 'vivid_2'
+ | 'vivid_3';
-type MatugenTheme = "light" | "dark";
+type MatugenTheme = 'light' | 'dark';
+
+export type ColorMapKey = keyof typeof defaultColorMap;
+export type ColorMapValue = (typeof defaultColorMap)[ColorMapKey];
diff --git a/lib/types/popupwindow.d.ts b/lib/types/popupwindow.d.ts
new file mode 100644
index 0000000..0c29706
--- /dev/null
+++ b/lib/types/popupwindow.d.ts
@@ -0,0 +1,35 @@
+import { Widget } from 'types/widgets/widget';
+import { WindowProps } from 'types/widgets/window';
+import { Transition } from './widget';
+
+export type PopupWindowProps = {
+ name: string;
+ child: any;
+ layout?: Layouts;
+ transition?: any;
+ exclusivity?: Exclusivity;
+} & WindowProps;
+
+export type LayoutFunction = (
+ name: string,
+ child: Widget,
+ transition: Transition,
+) => {
+ center: () => Widget;
+ top: () => Widget;
+ 'top-right': () => Widget;
+ 'top-center': () => Widget;
+ 'top-left': () => Widget;
+ 'bottom-left': () => Widget;
+ 'bottom-center': () => Widget;
+ 'bottom-right': () => Widget;
+};
+export type Layouts =
+ | 'center'
+ | 'top'
+ | 'top-right'
+ | 'top-center'
+ | 'top-left'
+ | 'bottom-left'
+ | 'bottom-center'
+ | 'bottom-right';
diff --git a/lib/types/power.d.ts b/lib/types/power.d.ts
index 5a44633..ef3c536 100644
--- a/lib/types/power.d.ts
+++ b/lib/types/power.d.ts
@@ -1 +1 @@
-export type Action = "sleep" | "reboot" | "logout" | "shutdown";
+export type Action = 'sleep' | 'reboot' | 'logout' | 'shutdown';
diff --git a/lib/types/powerprofiles.d.ts b/lib/types/powerprofiles.d.ts
new file mode 100644
index 0000000..a3592fa
--- /dev/null
+++ b/lib/types/powerprofiles.d.ts
@@ -0,0 +1,8 @@
+import icons from 'modules/icons/index';
+import PowerProfiles from 'types/service/powerprofiles.js';
+
+export type PowerProfiles = InstanceType;
+export type PowerProfile = 'power-saver' | 'balanced' | 'performance';
+export type PowerProfileObject = {
+ [key: string]: string;
+};
diff --git a/lib/types/systray.d.ts b/lib/types/systray.d.ts
new file mode 100644
index 0000000..e69de29
diff --git a/lib/types/utils.d.ts b/lib/types/utils.d.ts
new file mode 100644
index 0000000..884d339
--- /dev/null
+++ b/lib/types/utils.d.ts
@@ -0,0 +1,6 @@
+import { substitutes } from 'lib/icons';
+
+type SubstituteKeys = keyof typeof substitutes;
+
+export type ThrottleFn = (cmd: string, fn: ((output: string) => void) | undefined) => void;
+export type ThrottleFnCallback = ((output: string) => void) | undefined;
diff --git a/lib/types/variable.d.ts b/lib/types/variable.d.ts
new file mode 100644
index 0000000..af540dd
--- /dev/null
+++ b/lib/types/variable.d.ts
@@ -0,0 +1 @@
+export type Bind = OriginalBinding, unknown>;
diff --git a/lib/types/volume.d.ts b/lib/types/volume.d.ts
new file mode 100644
index 0000000..5e2cf32
--- /dev/null
+++ b/lib/types/volume.d.ts
@@ -0,0 +1,3 @@
+export type VolumeIcons = {
+ [index: number]: string;
+};
diff --git a/lib/types/weather.d.ts b/lib/types/weather.d.ts
index 54753ab..daf0e1a 100644
--- a/lib/types/weather.d.ts
+++ b/lib/types/weather.d.ts
@@ -1,10 +1,12 @@
-export type UnitType = "imperial" | "metric";
+import { weatherIcons } from 'modules/icons/weather';
+
+export type UnitType = 'imperial' | 'metric';
export type Weather = {
location: Location;
current: Current;
forecast: Forecast;
-}
+};
export type Current = {
last_updated_epoch?: number;
@@ -43,17 +45,17 @@ export type Current = {
chance_of_rain?: number;
will_it_snow?: number;
chance_of_snow?: number;
-}
+};
export type Condition = {
text: string;
icon: string;
code: number;
-}
+};
export type Forecast = {
forecastday: Forecastday[];
-}
+};
export type Forecastday = {
date: string;
@@ -61,7 +63,7 @@ export type Forecastday = {
day: Day;
astro: Astro;
hour: Current[];
-}
+};
export type Astro = {
sunrise: string;
@@ -72,7 +74,7 @@ export type Astro = {
moon_illumination: number;
is_moon_up: number;
is_sun_up: number;
-}
+};
export type Day = {
maxtemp_c: number;
@@ -95,7 +97,7 @@ export type Day = {
daily_chance_of_snow: number;
condition: Condition;
uv: number;
-}
+};
export type Location = {
name: string;
@@ -106,4 +108,11 @@ export type Location = {
tz_id: string;
localtime_epoch: number;
localtime: string;
-}
+};
+
+export type TemperatureIconColorMap = {
+ [key: number]: string;
+};
+
+export type WeatherIconTitle = keyof typeof weatherIcons;
+export type WeatherIcon = (typeof weatherIcons)[WeatherIconTitle];
diff --git a/lib/types/widget.d.ts b/lib/types/widget.d.ts
index 7fcda61..57dfd0b 100644
--- a/lib/types/widget.d.ts
+++ b/lib/types/widget.d.ts
@@ -1,3 +1,28 @@
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
+import Box from 'types/widgets/box';
+
export type Exclusivity = 'normal' | 'ignore' | 'exclusive';
-export type Anchor = "left" | "right" | "top" | "down";
-export type Transition = "none" | "crossfade" | "slide_right" | "slide_left" | "slide_up" | "slide_down";
+export type 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;
+
+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, event: Gdk.Event) => boolean | unknown;
diff --git a/lib/types/workspace.d.ts b/lib/types/workspace.d.ts
index 1117291..9c46c15 100644
--- a/lib/types/workspace.d.ts
+++ b/lib/types/workspace.d.ts
@@ -1,8 +1,25 @@
export type WorkspaceRule = {
- workspaceString: string,
- monitor: string,
-}
+ workspaceString: string;
+ monitor: string;
+};
export type WorkspaceMap = {
- [key: string]: number[],
-}
+ [key: string]: number[];
+};
+
+export type MonitorMap = {
+ [key: number]: string;
+};
+
+export type WorkspaceIcons = {
+ [key: string]: string;
+};
+
+export type WorkspaceIconsColored = {
+ [key: string]: {
+ color: string;
+ icon: string;
+ };
+};
+
+export type WorkspaceIconMap = WorkspaceIcons | WorkspaceIconsColored;
diff --git a/lib/utils.ts b/lib/utils.ts
index 10446b9..8c50008 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -1,59 +1,65 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
-import { type Application } from "types/service/applications"
-import { NotificationAnchor } from "./types/options"
-import { OSDAnchor } from "lib/types/options";
-import icons, { substitutes } from "./icons"
-import Gtk from "gi://Gtk?version=3.0"
-import Gdk from "gi://Gdk"
-import GLib from "gi://GLib?version=2.0"
-import GdkPixbuf from "gi://GdkPixbuf";
-import { NotificationArgs } from "types/utils/notify"
+import { type Application } from 'types/service/applications';
+import { NotificationAnchor } from './types/options';
+import { OSDAnchor } from 'lib/types/options';
+import icons, { substitutes } from './icons';
+import Gtk from 'gi://Gtk?version=3.0';
+import Gdk from 'gi://Gdk';
+import GLib from 'gi://GLib?version=2.0';
+import GdkPixbuf from 'gi://GdkPixbuf';
+import { NotificationArgs } from 'types/utils/notify';
+import { SubstituteKeys } from './types/utils';
+import { Window } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
+import { namedColors } from './constants/colors';
-export type Binding = import("types/service").Binding
+export type Binding = import('types/service').Binding;
/**
- * @returns substitute icon || name || fallback icon
- */
-export function icon(name: string | null, fallback = icons.missing) {
- if (!name)
- return fallback || ""
+ * @returns substitute icon || name || fallback icon
+ */
+export function icon(name: string | null, fallback = icons.missing): string {
+ const validateSubstitute = (name: string): name is SubstituteKeys => name in substitutes;
- if (GLib.file_test(name, GLib.FileTest.EXISTS))
- return name
+ if (!name) return fallback || '';
- const icon = (substitutes[name] || name)
- if (Utils.lookUpIcon(icon))
- return icon
+ if (GLib.file_test(name, GLib.FileTest.EXISTS)) return name;
- print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`)
- return fallback
+ let icon: string = name;
+
+ if (validateSubstitute(name)) {
+ icon = substitutes[name];
+ }
+
+ if (Utils.lookUpIcon(icon)) return icon;
+
+ print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`);
+ return fallback;
}
/**
* @returns execAsync(["bash", "-c", cmd])
*/
-export async function bash(strings: TemplateStringsArray | string, ...values: unknown[]) {
- const cmd = typeof strings === "string" ? strings : strings
- .flatMap((str, i) => str + `${values[i] ?? ""}`)
- .join("")
+export async function bash(strings: TemplateStringsArray | string, ...values: unknown[]): Promise {
+ const cmd =
+ typeof strings === 'string' ? strings : strings.flatMap((str, i) => str + `${values[i] ?? ''}`).join('');
- return Utils.execAsync(["bash", "-c", cmd]).catch(err => {
- console.error(cmd, err)
- return ""
- })
+ return Utils.execAsync(['bash', '-c', cmd]).catch((err) => {
+ console.error(cmd, err);
+ return '';
+ });
}
/**
* @returns execAsync(cmd)
*/
-export async function sh(cmd: string | string[]) {
- return Utils.execAsync(cmd).catch(err => {
- console.error(typeof cmd === "string" ? cmd : cmd.join(" "), err)
- return ""
- })
+export async function sh(cmd: string | string[]): Promise {
+ return Utils.execAsync(cmd).catch((err) => {
+ console.error(typeof cmd === 'string' ? cmd : cmd.join(' '), err);
+ return '';
+ });
}
-export function forMonitors(widget: (monitor: number) => Gtk.Window) {
+export function forMonitors(widget: (monitor: number) => Gtk.Window): Window[] {
const n = Gdk.Display.get_default()?.get_n_monitors() || 1;
return range(n, 0).flatMap(widget);
}
@@ -61,64 +67,62 @@ export function forMonitors(widget: (monitor: number) => Gtk.Window) {
/**
* @returns [start...length]
*/
-export function range(length: number, start = 1) {
- return Array.from({ length }, (_, i) => i + start)
+export function range(length: number, start = 1): number[] {
+ return Array.from({ length }, (_, i) => i + start);
}
/**
* @returns true if all of the `bins` are found
*/
-export function dependencies(...bins: string[]) {
- const missing = bins.filter(bin => Utils.exec({
- cmd: `which ${bin}`,
- out: () => false,
- err: () => true,
- }))
+export function dependencies(...bins: string[]): boolean {
+ const missing = bins.filter((bin) =>
+ Utils.exec({
+ cmd: `which ${bin}`,
+ out: () => false,
+ err: () => true,
+ }),
+ );
if (missing.length > 0) {
- console.warn(Error(`missing dependencies: ${missing.join(", ")}`))
+ console.warn(Error(`missing dependencies: ${missing.join(', ')}`));
Notify({
- summary: "Dependencies not found!",
- body: `The following dependencies are missing: ${missing.join(", ")}`,
+ summary: 'Dependencies not found!',
+ body: `The following dependencies are missing: ${missing.join(', ')}`,
iconName: icons.ui.warning,
- timeout: 7000
+ timeout: 7000,
});
}
- return missing.length === 0
+ return missing.length === 0;
}
/**
* run app detached
*/
-export function launchApp(app: Application) {
+export function launchApp(app: Application): void {
const exe = app.executable
.split(/\s+/)
- .filter(str => !str.startsWith("%") && !str.startsWith("@"))
- .join(" ")
+ .filter((str) => !str.startsWith('%') && !str.startsWith('@'))
+ .join(' ');
- bash(`${exe} &`)
- app.frequency += 1
+ bash(`${exe} &`);
+ app.frequency += 1;
}
/**
* to use with drag and drop
*/
-export function createSurfaceFromWidget(widget: Gtk.Widget) {
+export function createSurfaceFromWidget(widget: Gtk.Widget): GdkPixbuf.Pixbuf {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- const cairo = imports.gi.cairo as any
- const alloc = widget.get_allocation()
- const surface = new cairo.ImageSurface(
- cairo.Format.ARGB32,
- alloc.width,
- alloc.height,
- )
- const cr = new cairo.Context(surface)
- cr.setSourceRGBA(255, 255, 255, 0)
- cr.rectangle(0, 0, alloc.width, alloc.height)
- cr.fill()
- widget.draw(cr)
- return surface
+ const cairo = imports.gi.cairo as any;
+ const alloc = widget.get_allocation();
+ const surface = new cairo.ImageSurface(cairo.Format.ARGB32, alloc.width, alloc.height);
+ const cr = new cairo.Context(surface);
+ cr.setSourceRGBA(255, 255, 255, 0);
+ cr.rectangle(0, 0, alloc.width, alloc.height);
+ cr.fill();
+ widget.draw(cr);
+ return surface;
}
/**
@@ -129,9 +133,10 @@ export const isAnImage = (imgFilePath: string): boolean => {
GdkPixbuf.Pixbuf.new_from_file(imgFilePath);
return true;
} catch (error) {
+ console.error(error);
return false;
}
-}
+};
export const Notify = (notifPayload: NotificationArgs): void => {
let command = 'notify-send';
@@ -145,20 +150,42 @@ export const Notify = (notifPayload: NotificationArgs): void => {
if (notifPayload.transient) command += ` -e`;
if (notifPayload.id !== undefined) command += ` -r ${notifPayload.id}`;
- Utils.execAsync(command)
-}
+ Utils.execAsync(command);
+};
-export function getPosition(pos: NotificationAnchor | OSDAnchor): ("top" | "bottom" | "left" | "right")[] {
- const positionMap: { [key: string]: ("top" | "bottom" | "left" | "right")[] } = {
- "top": ["top"],
- "top right": ["top", "right"],
- "top left": ["top", "left"],
- "bottom": ["bottom"],
- "bottom right": ["bottom", "right"],
- "bottom left": ["bottom", "left"],
- "right": ["right"],
- "left": ["left"],
+export function getPosition(pos: NotificationAnchor | OSDAnchor): ('top' | 'bottom' | 'left' | 'right')[] {
+ const positionMap: { [key: string]: ('top' | 'bottom' | 'left' | 'right')[] } = {
+ top: ['top'],
+ 'top right': ['top', 'right'],
+ 'top left': ['top', 'left'],
+ bottom: ['bottom'],
+ 'bottom right': ['bottom', 'right'],
+ 'bottom left': ['bottom', 'left'],
+ right: ['right'],
+ left: ['left'],
};
- return positionMap[pos] || ["top"];
+ return positionMap[pos] || ['top'];
}
+export const isValidGjsColor = (color: string): boolean => {
+ const colorLower = color.toLowerCase().trim();
+
+ if (namedColors.has(colorLower)) {
+ return true;
+ }
+
+ const hexColorRegex = /^#(?:[a-fA-F0-9]{3,4}|[a-fA-F0-9]{6,8})$/;
+
+ const rgbRegex = /^rgb\(\s*(\d{1,3}%?\s*,\s*){2}\d{1,3}%?\s*\)$/;
+ const rgbaRegex = /^rgba\(\s*(\d{1,3}%?\s*,\s*){3}(0|1|0?\.\d+)\s*\)$/;
+
+ if (hexColorRegex.test(color)) {
+ return true;
+ }
+
+ if (rgbRegex.test(colorLower) || rgbaRegex.test(colorLower)) {
+ return true;
+ }
+
+ return false;
+};
diff --git a/lib/variables.ts b/lib/variables.ts
index 71c47b4..303c121 100644
--- a/lib/variables.ts
+++ b/lib/variables.ts
@@ -1,16 +1,15 @@
-import GLib from "gi://GLib"
+import GLib from 'gi://GLib';
+import { DateTime } from 'types/@girs/glib-2.0/glib-2.0.cjs';
export const clock = Variable(GLib.DateTime.new_now_local(), {
- poll: [1000, () => GLib.DateTime.new_now_local()],
-})
+ poll: [1000, (): DateTime => GLib.DateTime.new_now_local()],
+});
export const uptime = Variable(0, {
- poll: [60_000, "cat /proc/uptime", line =>
- Number.parseInt(line.split(".")[0]) / 60,
- ],
-})
+ poll: [60_000, 'cat /proc/uptime', (line): number => Number.parseInt(line.split('.')[0]) / 60],
+});
export const distro = {
- id: GLib.get_os_info("ID"),
- logo: GLib.get_os_info("LOGO"),
-}
+ id: GLib.get_os_info('ID'),
+ logo: GLib.get_os_info('LOGO'),
+};
diff --git a/main.ts b/main.ts
index 8e55a66..6f995a6 100644
--- a/main.ts
+++ b/main.ts
@@ -1,27 +1,21 @@
-import "lib/session";
-import "scss/style";
-import "globals/useTheme";
-import "globals/mousePos";
+import 'lib/session';
+import 'scss/style';
+import 'globals/useTheme';
+import 'globals/mousePos';
-import { Bar } from "modules/bar/Bar";
-import MenuWindows from "./modules/menus/main.js";
-import SettingsDialog from "widget/settings/SettingsDialog";
-import Notifications from "./modules/notifications/index.js";
-import { forMonitors } from "lib/utils";
-import OSD from "modules/osd/index";
+import { Bar } from 'modules/bar/Bar';
+import MenuWindows from './modules/menus/main.js';
+import SettingsDialog from 'widget/settings/SettingsDialog';
+import Notifications from './modules/notifications/index.js';
+import { forMonitors } from 'lib/utils';
+import OSD from 'modules/osd/index';
App.config({
onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`),
- windows: [
- ...MenuWindows,
- Notifications(),
- SettingsDialog(),
- ...forMonitors(Bar),
- OSD(),
- ],
+ windows: [...MenuWindows, Notifications(), SettingsDialog(), ...forMonitors(Bar), OSD()],
closeWindowDelay: {
sideright: 350,
launcher: 350,
bar0: 350,
},
-})
+});
diff --git a/modules/bar/Bar.ts b/modules/bar/Bar.ts
index b3b4f43..7898985 100644
--- a/modules/bar/Bar.ts
+++ b/modules/bar/Bar.ts
@@ -1,8 +1,10 @@
-const hyprland = await Service.import("hyprland");
+const hyprland = await Service.import('hyprland');
import {
Menu,
- Workspaces, ClientTitle, Media,
+ Workspaces,
+ ClientTitle,
+ Media,
Notifications,
Volume,
Network,
@@ -20,121 +22,114 @@ import {
Updates,
Weather,
Power,
-} from "./Exports"
+} from './Exports';
-import { BarItemBox as WidgetContainer } from "../shared/barItemBox.js";
-import options from "options";
-import Gdk from "gi://Gdk?version=3.0";
-import Button from "types/widgets/button.js";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0.js";
+import { BarItemBox as WidgetContainer } from '../shared/barItemBox.js';
+import options from 'options';
+import Gdk from 'gi://Gdk?version=3.0';
+import Button from 'types/widgets/button.js';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0.js';
import './SideEffects';
+import { WindowLayer } from 'lib/types/options.js';
+import { Attribute, Child } from 'lib/types/widget.js';
+import Window from 'types/widgets/window.js';
const { layouts } = options.bar;
+const { location } = options.theme.bar;
export type BarWidget = keyof typeof widget;
-type Section = "battery"
- | "dashboard"
- | "workspaces"
- | "windowtitle"
- | "media"
- | "notifications"
- | "volume"
- | "network"
- | "bluetooth"
- | "clock"
- | "Ram"
- | "Cpu"
- | "Storage"
- | "Netstat"
- | "KbInput"
- | "Updates"
- | "Weather"
- | "Power"
- | "systray";
+type Section =
+ | 'battery'
+ | 'dashboard'
+ | 'workspaces'
+ | 'windowtitle'
+ | 'media'
+ | 'notifications'
+ | 'volume'
+ | 'network'
+ | 'bluetooth'
+ | 'clock'
+ | 'ram'
+ | 'cpu'
+ | 'storage'
+ | 'netstat'
+ | 'kbinput'
+ | 'updates'
+ | 'weather'
+ | 'power'
+ | 'systray';
type Layout = {
- left: Section[],
- middle: Section[],
- right: Section[],
-}
+ left: Section[];
+ middle: Section[];
+ right: Section[];
+};
type BarLayout = {
- [key: string]: Layout
-}
+ [key: string]: Layout;
+};
-const getModulesForMonitor = (monitor: number, curLayouts: BarLayout) => {
- const foundMonitor = Object.keys(curLayouts).find(mon => mon === monitor.toString());
+const getLayoutForMonitor = (monitor: number, layouts: BarLayout): Layout => {
+ const matchingKey = Object.keys(layouts).find((key) => key === monitor.toString());
+ const wildcard = Object.keys(layouts).find((key) => key === '*');
- const defaultSetup: Layout = {
- left: [
- "dashboard",
- "workspaces",
- "windowtitle"
- ],
- middle: [
- "media"
- ],
- right: [
- "volume",
- "network",
- "bluetooth",
- "battery",
- "systray",
- "clock",
- "notifications"
- ]
+ if (matchingKey) {
+ return layouts[matchingKey];
}
- if (foundMonitor === undefined) {
- return defaultSetup;
+ if (wildcard) {
+ return layouts[wildcard];
}
- return curLayouts[foundMonitor];
-
-}
+ return {
+ left: ['dashboard', 'workspaces', 'windowtitle'],
+ middle: ['media'],
+ right: ['volume', 'network', 'bluetooth', 'battery', 'systray', 'clock', 'notifications'],
+ };
+};
const widget = {
- battery: () => WidgetContainer(BatteryLabel()),
- dashboard: () => WidgetContainer(Menu()),
- workspaces: (monitor: number) => WidgetContainer(Workspaces(monitor)),
- windowtitle: () => WidgetContainer(ClientTitle()),
- media: () => WidgetContainer(Media()),
- notifications: () => WidgetContainer(Notifications()),
- volume: () => WidgetContainer(Volume()),
- network: () => WidgetContainer(Network()),
- bluetooth: () => WidgetContainer(Bluetooth()),
- clock: () => WidgetContainer(Clock()),
- systray: () => WidgetContainer(SysTray()),
- ram: () => WidgetContainer(Ram()),
- cpu: () => WidgetContainer(Cpu()),
- storage: () => WidgetContainer(Storage()),
- netstat: () => WidgetContainer(Netstat()),
- kbinput: () => WidgetContainer(KbInput()),
- updates: () => WidgetContainer(Updates()),
- weather: () => WidgetContainer(Weather()),
- power: () => WidgetContainer(Power()),
+ battery: (): Button => WidgetContainer(BatteryLabel()),
+ dashboard: (): Button => WidgetContainer(Menu()),
+ workspaces: (monitor: number): Button => WidgetContainer(Workspaces(monitor)),
+ windowtitle: (): Button => WidgetContainer(ClientTitle()),
+ media: (): Button => WidgetContainer(Media()),
+ notifications: (): Button => WidgetContainer(Notifications()),
+ volume: (): Button => WidgetContainer(Volume()),
+ network: (): Button => WidgetContainer(Network()),
+ bluetooth: (): Button => WidgetContainer(Bluetooth()),
+ clock: (): Button => WidgetContainer(Clock()),
+ systray: (): Button => WidgetContainer(SysTray()),
+ ram: (): Button => WidgetContainer(Ram()),
+ cpu: (): Button => WidgetContainer(Cpu()),
+ storage: (): Button => WidgetContainer(Storage()),
+ netstat: (): Button => WidgetContainer(Netstat()),
+ kbinput: (): Button => WidgetContainer(KbInput()),
+ updates: (): Button => WidgetContainer(Updates()),
+ weather: (): Button => WidgetContainer(Weather()),
+ power: (): Button => WidgetContainer(Power()),
};
type GdkMonitors = {
[key: string]: {
- key: string,
- model: string,
- used: boolean
- }
+ key: string;
+ model: string;
+ used: boolean;
+ };
};
function getGdkMonitors(): GdkMonitors {
const display = Gdk.Display.get_default();
if (display === null) {
- console.error("Failed to get Gdk display.");
+ console.error('Failed to get Gdk display.');
return {};
}
const numGdkMonitors = display.get_n_monitors();
- const gdkMonitors = {};
+ const gdkMonitors: GdkMonitors = {};
for (let i = 0; i < numGdkMonitors; i++) {
const curMonitor = display.get_monitor(i);
@@ -144,7 +139,7 @@ function getGdkMonitors(): GdkMonitors {
continue;
}
- const model = curMonitor.get_model();
+ const model = curMonitor.get_model() || '';
const geometry = curMonitor.get_geometry();
const scaleFactor = curMonitor.get_scale_factor();
@@ -159,35 +154,35 @@ function getGdkMonitors(): GdkMonitors {
* NOTE: Some more funky stuff being done by GDK.
* We render windows/bar based on the monitor ID. So if you have 3 monitors, then your
* monitor IDs will be [0, 1, 2]. Hyprland will NEVER change what ID belongs to what monitor.
- *
+ *
* So if hyprland determines id 0 = DP-1, even after you unplug, shut off or restart your monitor,
* the id 0 will ALWAYS be DP-1.
- *
+ *
* However, GDK (the righteous genius that it is) will change the order of ID anytime your monitor
* setup is changed. So if you unplug your monitor and plug it back it, it now becomes the last id.
* So if DP-1 was id 0 and you unplugged it, it will reconfigure to id 2. This sucks because now
* there's a mismtach between what GDK determines the monitor is at id 2 and what Hyprland determines
* is at id 2.
- *
+ *
* So for that reason, we need to redirect the input `monitor` that the Bar module takes in, to the
* proper Hyprland monitor. So when monitor id 0 comes in, we need to find what the id of that monitor
* is being determined as by Hyprland so the bars show up on the right monitors.
- *
+ *
* Since GTK3 doesn't contain connection names and only monitor models, we have to make the best guess
* in the case that there are multiple models in the same resolution with the same scale. We find the
* 'right' monitor by checking if the model matches along with the resolution and scale. If monitor at
* ID 0 for GDK is being reported as 'MSI MAG271CQR' we find the same model in the Hyprland monitor list
* and check if the resolution and scaling is the same... if it is then we determine it's a match.
- *
+ *
* The edge-case that we just can't handle is if you have the same monitors in the same resolution at the same
* scale. So if you've got 2 'MSI MAG271CQR' monitors at 2560x1440 at scale 1, then we just match the first
- * monitor in the list as the first match and then the second 'MSI MAG271CQR' as a match in the 2nd iteration.
- * You may have the bar showing up on the wrong one in this case because we don't know what the connector id
+ * monitor in the list as the first match and then the second 'MSI MAG271CQR' as a match in the 2nd iteration.
+ * You may have the bar showing up on the wrong one in this case because we don't know what the connector id
* is of either of these monitors (DP-1, DP-2) which are unique values - as these are only in GTK4.
- *
+ *
* Keep in mind though, this is ONLY an issue if you change your monitor setup by plugging in a new one, restarting
* an existing one or shutting it off.
- *
+ *
* If your monitors aren't changed in the current session you're in then none of this safeguarding is relevant.
*
* Fun stuff really... :facepalm:
@@ -197,7 +192,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set {
+ const directMatch = hyprland.monitors.find((hypMon) => {
const hyprlandKey = `${hypMon.model}_${hypMon.width}x${hypMon.height}_${hypMon.scale}`;
return gdkMonitor.key.startsWith(hyprlandKey) && !usedHyprlandMonitors.has(hypMon.id) && hypMon.id === monitor;
});
@@ -216,7 +211,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set {
+ const hyprlandMonitor = hyprland.monitors.find((hypMon) => {
const hyprlandKey = `${hypMon.model}_${hypMon.width}x${hypMon.height}_${hypMon.scale}`;
return gdkMonitor.key.startsWith(hyprlandKey) && !usedHyprlandMonitors.has(hypMon.id);
});
@@ -227,7 +222,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set !usedHyprlandMonitors.has(hypMon.id));
+ const fallbackMonitor = hyprland.monitors.find((hypMon) => !usedHyprlandMonitors.has(hypMon.id));
if (fallbackMonitor) {
usedHyprlandMonitors.add(fallbackMonitor.id);
@@ -250,49 +245,63 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set {
const usedHyprlandMonitors = new Set();
- return (monitor: number) => {
+ return (monitor: number): Window => {
const hyprlandMonitor = gdkMonitorIdToHyprlandId(monitor, usedHyprlandMonitors);
return Widget.Window({
name: `bar-${hyprlandMonitor}`,
- class_name: "bar",
+ class_name: 'bar',
monitor,
visible: true,
- anchor: ["top", "left", "right"],
- exclusivity: "exclusive",
- layer: options.theme.bar.layer.bind("value"),
+ anchor: location.bind('value').as((ln) => [ln, 'left', 'right']),
+ exclusivity: 'exclusive',
+ layer: Utils.merge(
+ [options.theme.bar.layer.bind('value'), options.tear.bind('value')],
+ (barLayer: WindowLayer, tear: boolean) => {
+ if (tear && barLayer === 'overlay') {
+ return 'top';
+ }
+ return barLayer;
+ },
+ ),
child: Widget.Box({
class_name: 'bar-panel-container',
child: Widget.CenterBox({
class_name: 'bar-panel',
css: 'padding: 1px',
startWidget: Widget.Box({
- class_name: "box-left",
+ class_name: 'box-left',
hexpand: true,
- setup: self => {
+ setup: (self) => {
self.hook(layouts, (self) => {
- const foundLayout = getModulesForMonitor(hyprlandMonitor, layouts.value as BarLayout);
- self.children = foundLayout.left.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button);
+ 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);
});
},
}),
centerWidget: Widget.Box({
- class_name: "box-center",
- hpack: "center",
- setup: self => {
+ class_name: 'box-center',
+ hpack: 'center',
+ setup: (self) => {
self.hook(layouts, (self) => {
- const foundLayout = getModulesForMonitor(hyprlandMonitor, layouts.value as BarLayout);
- self.children = foundLayout.middle.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button);
+ 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);
});
},
}),
endWidget: Widget.Box({
- class_name: "box-right",
- hpack: "end",
- setup: self => {
+ class_name: 'box-right',
+ hpack: 'end',
+ setup: (self) => {
self.hook(layouts, (self) => {
- const foundLayout = getModulesForMonitor(hyprlandMonitor, layouts.value as BarLayout);
- self.children = foundLayout.right.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button);
+ 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);
});
},
}),
diff --git a/modules/bar/Exports.ts b/modules/bar/Exports.ts
index 9990bb4..c6a540a 100644
--- a/modules/bar/Exports.ts
+++ b/modules/bar/Exports.ts
@@ -1,24 +1,24 @@
-import { Menu } from "./menu/index";
-import { Workspaces } from "./workspaces/index";
-import { ClientTitle } from "./window_title/index";
-import { Media } from "./media/index";
-import { Notifications } from "./notifications/index";
-import { Volume } from "./volume/index";
-import { Network } from "./network/index";
-import { Bluetooth } from "./bluetooth/index";
-import { BatteryLabel } from "./battery/index";
-import { Clock } from "./clock/index";
-import { SysTray } from "./systray/index";
+import { Menu } from './menu/index';
+import { Workspaces } from './workspaces/index';
+import { ClientTitle } from './window_title/index';
+import { Media } from './media/index';
+import { Notifications } from './notifications/index';
+import { Volume } from './volume/index';
+import { Network } from './network/index';
+import { Bluetooth } from './bluetooth/index';
+import { BatteryLabel } from './battery/index';
+import { Clock } from './clock/index';
+import { SysTray } from './systray/index';
// Custom Modules
-import { Ram } from "../../customModules/ram/index";
-import { Cpu } from "../../customModules/cpu/index";
-import { Storage } from "customModules/storage/index";
-import { Netstat } from "customModules/netstat/index";
-import { KbInput } from "customModules/kblayout/index";
-import { Updates } from "customModules/updates/index";
-import { Weather } from "customModules/weather/index";
-import { Power } from "customModules/power/index";
+import { Ram } from '../../customModules/ram/index';
+import { Cpu } from '../../customModules/cpu/index';
+import { Storage } from 'customModules/storage/index';
+import { Netstat } from 'customModules/netstat/index';
+import { KbInput } from 'customModules/kblayout/index';
+import { Updates } from 'customModules/updates/index';
+import { Weather } from 'customModules/weather/index';
+import { Power } from 'customModules/power/index';
export {
Menu,
diff --git a/modules/bar/SideEffects.ts b/modules/bar/SideEffects.ts
index 2a30311..8b055bf 100644
--- a/modules/bar/SideEffects.ts
+++ b/modules/bar/SideEffects.ts
@@ -1,14 +1,14 @@
-import options from "options";
+import options from 'options';
const { showIcon, showTime } = options.bar.clock;
-showIcon.connect("changed", () => {
+showIcon.connect('changed', () => {
if (!showTime.value && !showIcon.value) {
showTime.value = true;
}
});
-showTime.connect("changed", () => {
+showTime.connect('changed', () => {
if (!showTime.value && !showIcon.value) {
showIcon.value = true;
}
diff --git a/modules/bar/battery/index.ts b/modules/bar/battery/index.ts
index e35c511..98ed650 100644
--- a/modules/bar/battery/index.ts
+++ b/modules/bar/battery/index.ts
@@ -1,34 +1,37 @@
-const battery = await Service.import("battery");
+const battery = await Service.import('battery');
import Gdk from 'gi://Gdk?version=3.0';
-import { openMenu } from "../utils.js";
-import options from "options";
+import { openMenu } from '../utils.js';
+import options from 'options';
+import { BarBoxChild } from 'lib/types/bar.js';
+import Button from 'types/widgets/button.js';
+import { Child } from 'lib/types/widget.js';
const { label: show_label } = options.bar.battery;
-const BatteryLabel = () => {
+const BatteryLabel = (): BarBoxChild => {
const isVis = Variable(battery.available);
- const batIcon = Utils.merge([battery.bind("percent"), battery.bind("charging"), battery.bind("charged")],
+ const batIcon = Utils.merge(
+ [battery.bind('percent'), battery.bind('charging'), battery.bind('charged')],
(batPercent: number, batCharging, batCharged) => {
- if (batCharged)
- return `battery-level-100-charged-symbolic`;
- else
- return `battery-level-${Math.floor(batPercent / 10) * 10}${batCharging ? '-charging' : ''}-symbolic`;
- });
+ if (batCharged) return `battery-level-100-charged-symbolic`;
+ else return `battery-level-${Math.floor(batPercent / 10) * 10}${batCharging ? '-charging' : ''}-symbolic`;
+ },
+ );
- battery.connect("changed", ({ available }) => {
+ battery.connect('changed', ({ available }) => {
isVis.value = available;
});
- const formatTime = (seconds: number) => {
+ const formatTime = (seconds: number): Record => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
return { hours, minutes };
};
- const generateTooltip = (timeSeconds: number, isCharging: boolean, isCharged: boolean) => {
+ const generateTooltip = (timeSeconds: number, isCharging: boolean, isCharged: boolean): string => {
if (isCharged) {
- return "Fully Charged!!!";
+ return 'Fully Charged!!!';
}
const { hours, minutes } = formatTime(timeSeconds);
@@ -41,59 +44,56 @@ const BatteryLabel = () => {
return {
component: Widget.Box({
- className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_label.bind("value")], (style, showLabel) => {
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
- return `battery ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
- }),
- visible: battery.bind("available"),
- tooltip_text: battery.bind("time_remaining").as((t) => t.toString()),
- children: Utils.merge(
- [battery.bind("available"), show_label.bind("value")],
- (batAvail, showLabel) => {
- if (batAvail && showLabel) {
- return [
- Widget.Icon({
- class_name: "bar-button-icon battery",
- icon: batIcon
- }),
- Widget.Label({
- class_name: "bar-button-label battery",
- label: battery.bind("percent").as((p) => `${Math.floor(p)}%`),
- }),
- ];
- } else if (batAvail && !showLabel) {
- return [
- Widget.Icon({
- class_name: "bar-button-icon battery",
- icon: batIcon
- })
- ];
- } else {
- return [];
- }
+ className: Utils.merge(
+ [options.theme.bar.buttons.style.bind('value'), show_label.bind('value')],
+ (style, showLabel) => {
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `battery ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
},
),
+ visible: battery.bind('available'),
+ tooltip_text: battery.bind('time_remaining').as((t) => t.toString()),
+ children: Utils.merge([battery.bind('available'), show_label.bind('value')], (batAvail, showLabel) => {
+ if (batAvail && showLabel) {
+ return [
+ Widget.Icon({
+ class_name: 'bar-button-icon battery',
+ icon: batIcon,
+ }),
+ Widget.Label({
+ class_name: 'bar-button-label battery',
+ label: battery.bind('percent').as((p) => `${Math.floor(p)}%`),
+ }),
+ ];
+ } else if (batAvail && !showLabel) {
+ return [
+ Widget.Icon({
+ class_name: 'bar-button-icon battery',
+ icon: batIcon,
+ }),
+ ];
+ } else {
+ return [];
+ }
+ }),
setup: (self) => {
self.hook(battery, () => {
if (battery.available) {
- self.tooltip_text = generateTooltip(
- battery.time_remaining,
- battery.charging,
- battery.charged,
- );
+ self.tooltip_text = generateTooltip(battery.time_remaining, battery.charging, battery.charged);
}
});
},
}),
isVis,
- boxClass: "battery",
+ boxClass: 'battery',
props: {
- on_primary_click: (clicked: any, event: Gdk.Event) => {
- openMenu(clicked, event, "energymenu");
+ on_primary_click: (clicked: Button, event: Gdk.Event): void => {
+ openMenu(clicked, event, 'energymenu');
},
},
};
diff --git a/modules/bar/bluetooth/index.ts b/modules/bar/bluetooth/index.ts
index 8d1662b..c9cbb45 100644
--- a/modules/bar/bluetooth/index.ts
+++ b/modules/bar/bluetooth/index.ts
@@ -1,41 +1,41 @@
-const bluetooth = await Service.import('bluetooth')
+const bluetooth = await Service.import('bluetooth');
import Gdk from 'gi://Gdk?version=3.0';
-import options from "options";
-import { openMenu } from "../utils.js";
+import options from 'options';
+import { openMenu } from '../utils.js';
+import { BarBoxChild } from 'lib/types/bar.js';
+import Button from 'types/widgets/button.js';
+import { Child } from 'lib/types/widget.js';
const { label } = options.bar.bluetooth;
-const Bluetooth = () => {
+const Bluetooth = (): BarBoxChild => {
const btIcon = Widget.Label({
- label: bluetooth.bind("enabled").as((v) => v ? "" : ""),
- class_name: "bar-button-icon bluetooth txt-icon bar",
+ label: bluetooth.bind('enabled').as((v) => (v ? '' : '')),
+ class_name: 'bar-button-icon bluetooth txt-icon bar',
});
const btText = Widget.Label({
- label: Utils.merge([
- bluetooth.bind("enabled"),
- bluetooth.bind("connected_devices"),
- ],
- (btEnabled, btDevices) => {
- return btEnabled && btDevices.length ? ` Connected (${btDevices.length})`
- : btEnabled ? "On"
- : "Off"
-
- }),
- class_name: "bar-button-label bluetooth",
+ label: Utils.merge([bluetooth.bind('enabled'), bluetooth.bind('connected_devices')], (btEnabled, btDevices) => {
+ return btEnabled && btDevices.length ? ` Connected (${btDevices.length})` : btEnabled ? 'On' : 'Off';
+ }),
+ class_name: 'bar-button-label bluetooth',
});
return {
component: Widget.Box({
- className: Utils.merge([options.theme.bar.buttons.style.bind("value"), label.bind("value")], (style, showLabel) => {
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
- return `bluetooth ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
- }),
- children: options.bar.bluetooth.label.bind("value").as((showLabel) => {
+ className: Utils.merge(
+ [options.theme.bar.buttons.style.bind('value'), label.bind('value')],
+ (style, showLabel) => {
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `bluetooth ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
+ },
+ ),
+ children: options.bar.bluetooth.label.bind('value').as((showLabel) => {
if (showLabel) {
return [btIcon, btText];
}
@@ -43,14 +43,13 @@ const Bluetooth = () => {
}),
}),
isVisible: true,
- boxClass: "bluetooth",
+ boxClass: 'bluetooth',
props: {
- on_primary_click: (clicked: any, event: Gdk.Event) => {
- openMenu(clicked, event, "bluetoothmenu");
+ on_primary_click: (clicked: Button, event: Gdk.Event): void => {
+ openMenu(clicked, event, 'bluetoothmenu');
},
},
};
+};
-}
-
-export { Bluetooth }
+export { Bluetooth };
diff --git a/modules/bar/clock/index.ts b/modules/bar/clock/index.ts
index fb99e3f..c55a505 100644
--- a/modules/bar/clock/index.ts
+++ b/modules/bar/clock/index.ts
@@ -1,44 +1,46 @@
import Gdk from 'gi://Gdk?version=3.0';
-import GLib from "gi://GLib";
-import { openMenu } from "../utils.js";
-import options from "options";
+import GLib from 'gi://GLib';
+import { openMenu } from '../utils.js';
+import options from 'options';
+import { DateTime } from 'types/@girs/glib-2.0/glib-2.0.cjs';
+import { BarBoxChild } from 'lib/types/bar.js';
+import Button from 'types/widgets/button.js';
+import { Child } from 'lib/types/widget.js';
const { format, icon, showIcon, showTime } = options.bar.clock;
const { style } = options.theme.bar.buttons;
-
const date = Variable(GLib.DateTime.new_now_local(), {
- poll: [1000, () => GLib.DateTime.new_now_local()],
+ poll: [1000, (): DateTime => GLib.DateTime.new_now_local()],
});
-const time = Utils.derive([date, format], (c, f) => c.format(f) || "");
-
-const Clock = () => {
+const time = Utils.derive([date, format], (c, f) => c.format(f) || '');
+const Clock = (): BarBoxChild => {
const clockTime = Widget.Label({
- class_name: "bar-button-label clock bar",
+ class_name: 'bar-button-label clock bar',
label: time.bind(),
});
const clockIcon = Widget.Label({
- label: icon.bind("value"),
- class_name: "bar-button-icon clock txt-icon bar",
+ label: icon.bind('value'),
+ class_name: 'bar-button-icon clock txt-icon bar',
});
return {
component: Widget.Box({
- className: Utils.merge([
- style.bind("value"),
- showIcon.bind("value"), showTime.bind("value")
- ], (btnStyle, shwIcn, shwLbl) => {
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
-
- return `bluetooth ${styleMap[btnStyle]} ${!shwLbl ? "no-label" : ""} ${!shwIcn ? "no-icon" : ""}`;
- }),
- children: Utils.merge([showIcon.bind("value"), showTime.bind("value")], (shIcn, shTm) => {
+ className: Utils.merge(
+ [style.bind('value'), showIcon.bind('value'), showTime.bind('value')],
+ (btnStyle, shwIcn, shwLbl) => {
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `bluetooth ${styleMap[btnStyle]} ${!shwLbl ? 'no-label' : ''} ${!shwIcn ? 'no-icon' : ''}`;
+ },
+ ),
+ children: Utils.merge([showIcon.bind('value'), showTime.bind('value')], (shIcn, shTm) => {
if (shIcn && !shTm) {
return [clockIcon];
} else if (shTm && !shIcn) {
@@ -46,13 +48,13 @@ const Clock = () => {
}
return [clockIcon, clockTime];
- })
+ }),
}),
isVisible: true,
- boxClass: "clock",
+ boxClass: 'clock',
props: {
- on_primary_click: (clicked: any, event: Gdk.Event) => {
- openMenu(clicked, event, "calendarmenu");
+ on_primary_click: (clicked: Button, event: Gdk.Event): void => {
+ openMenu(clicked, event, 'calendarmenu');
},
},
};
diff --git a/modules/bar/media/index.ts b/modules/bar/media/index.ts
index e7f5237..7266a5c 100644
--- a/modules/bar/media/index.ts
+++ b/modules/bar/media/index.ts
@@ -1,20 +1,23 @@
import Gdk from 'gi://Gdk?version=3.0';
-const mpris = await Service.import("mpris");
-import { openMenu } from "../utils.js";
-import options from "options";
+const mpris = await Service.import('mpris');
+import { openMenu } from '../utils.js';
+import options from 'options';
import { getCurrentPlayer } from 'lib/shared/media.js';
+import { BarBoxChild } from 'lib/types/bar.js';
+import Button from 'types/widgets/button.js';
+import { Child } from 'lib/types/widget.js';
const { show_artist, truncation, truncation_size, show_label, show_active_only } = options.bar.media;
-const Media = () => {
+const Media = (): BarBoxChild => {
const activePlayer = Variable(mpris.players[0]);
const isVis = Variable(!show_active_only.value);
- show_active_only.connect("changed", () => {
+ show_active_only.connect('changed', () => {
isVis.value = !show_active_only.value || mpris.players.length > 0;
});
- mpris.connect("changed", () => {
+ mpris.connect('changed', () => {
const curPlayer = getCurrentPlayer(activePlayer.value);
activePlayer.value = curPlayer;
isVis.value = !show_active_only.value || mpris.players.length > 0;
@@ -22,41 +25,37 @@ const Media = () => {
const getIconForPlayer = (playerName: string): string => {
const windowTitleMap = [
- ["Firefox", ""],
- ["Microsoft Edge", ""],
- ["Discord", ""],
- ["Plex", ""],
- ["Spotify", ""],
- ["(.*)", ""],
+ ['Firefox', ''],
+ ['Microsoft Edge', ''],
+ ['Discord', ''],
+ ['Plex', ''],
+ ['Spotify', ''],
+ ['(.*)', ''],
];
- const foundMatch = windowTitleMap.find((wt) =>
- RegExp(wt[0], "i").test(playerName),
- );
+ const foundMatch = windowTitleMap.find((wt) => RegExp(wt[0], 'i').test(playerName));
- return foundMatch ? foundMatch[1] : "";
+ return foundMatch ? foundMatch[1] : '';
};
- const songIcon = Variable("");
+ const songIcon = Variable('');
- const mediaLabel = Utils.watch("Media", [mpris, show_artist, truncation, truncation_size, show_label], () => {
+ const mediaLabel = Utils.watch('Media', [mpris, show_artist, truncation, truncation_size, show_label], () => {
if (activePlayer.value && show_label.value) {
const { track_title, identity, track_artists } = activePlayer.value;
songIcon.value = getIconForPlayer(identity);
- const trackArtist = show_artist.value
- ? ` - ${track_artists.join(', ')}`
- : ``;
+ const trackArtist = show_artist.value ? ` - ${track_artists.join(', ')}` : ``;
const truncatedLabel = truncation.value
? `${track_title + trackArtist}`.substring(0, truncation_size.value)
: `${track_title + trackArtist}`;
return track_title.length === 0
? `No media playing...`
- : ((truncatedLabel.length < truncation_size.value) || !truncation.value)
- ? `${truncatedLabel}`
- : `${truncatedLabel.substring(0, truncatedLabel.length - 3)}...`;
+ : truncatedLabel.length < truncation_size.value || !truncation.value
+ ? `${truncatedLabel}`
+ : `${truncatedLabel.substring(0, truncatedLabel.length - 3)}...`;
} else {
- songIcon.value = getIconForPlayer(activePlayer.value?.identity || "");
+ songIcon.value = getIconForPlayer(activePlayer.value?.identity || '');
return `Media`;
}
});
@@ -65,22 +64,26 @@ const Media = () => {
component: Widget.Box({
visible: false,
child: Widget.Box({
- className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_label.bind("value")], (style, showLabel) => {
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
- return `media ${styleMap[style]}`;
- }),
+ className: Utils.merge(
+ [options.theme.bar.buttons.style.bind('value'), show_label.bind('value')],
+ (style) => {
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `media ${styleMap[style]}`;
+ },
+ ),
child: Widget.Box({
children: [
Widget.Label({
- class_name: "bar-button-icon media txt-icon bar",
- label: songIcon.bind("value").as(v => v || ""),
+ class_name: 'bar-button-icon media txt-icon bar',
+ label: songIcon.bind('value').as((v) => v || ''),
}),
Widget.Label({
- class_name: "bar-button-label media",
+ class_name: 'bar-button-label media',
label: mediaLabel,
}),
],
@@ -88,13 +91,13 @@ const Media = () => {
}),
}),
isVis,
- boxClass: "media",
- name: "media",
+ boxClass: 'media',
+ name: 'media',
props: {
on_scroll_up: () => activePlayer.value?.next(),
on_scroll_down: () => activePlayer.value?.previous(),
- on_primary_click: (clicked: any, event: Gdk.Event) => {
- openMenu(clicked, event, "mediamenu");
+ on_primary_click: (clicked: Button, event: Gdk.Event): void => {
+ openMenu(clicked, event, 'mediamenu');
},
},
};
diff --git a/modules/bar/menu/index.ts b/modules/bar/menu/index.ts
index a258dc5..5612dc4 100644
--- a/modules/bar/menu/index.ts
+++ b/modules/bar/menu/index.ts
@@ -1,28 +1,32 @@
import Gdk from 'gi://Gdk?version=3.0';
-import { openMenu } from "../utils.js";
-import options from "options";
+import { openMenu } from '../utils.js';
+import options from 'options';
+import { BarBoxChild } from 'lib/types/bar.js';
+import Button from 'types/widgets/button.js';
+import { Child } from 'lib/types/widget.js';
-const Menu = () => {
+const Menu = (): BarBoxChild => {
return {
component: Widget.Box({
- className: Utils.merge([options.theme.bar.buttons.style.bind("value")], (style) => {
+ className: Utils.merge([options.theme.bar.buttons.style.bind('value')], (style) => {
const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
};
return `dashboard ${styleMap[style]}`;
}),
child: Widget.Label({
- class_name: "bar-menu_label bar-button_icon txt-icon bar",
- label: options.bar.launcher.icon.bind("value"),
+ class_name: 'bar-menu_label bar-button_icon txt-icon bar',
+ label: options.bar.launcher.icon.bind('value'),
}),
}),
isVisible: true,
- boxClass: "dashboard",
+ boxClass: 'dashboard',
props: {
- on_primary_click: (clicked: any, event: Gdk.Event) => {
- openMenu(clicked, event, "dashboardmenu");
+ on_primary_click: (clicked: Button, event: Gdk.Event): void => {
+ openMenu(clicked, event, 'dashboardmenu');
},
},
};
diff --git a/modules/bar/network/index.ts b/modules/bar/network/index.ts
index da944fa..24c11b8 100644
--- a/modules/bar/network/index.ts
+++ b/modules/bar/network/index.ts
@@ -1,69 +1,77 @@
import Gdk from 'gi://Gdk?version=3.0';
-const network = await Service.import("network");
-import options from "options";
-import { openMenu } from "../utils.js";
+const network = await Service.import('network');
+import options from 'options';
+import { openMenu } from '../utils.js';
+import { BarBoxChild } from 'lib/types/bar.js';
+import Button from 'types/widgets/button.js';
+import { Child } from 'lib/types/widget.js';
const { label: networkLabel, truncation, truncation_size } = options.bar.network;
-const Network = () => {
+const Network = (): BarBoxChild => {
return {
component: Widget.Box({
- vpack: "fill",
+ vpack: 'fill',
vexpand: true,
- className: Utils.merge([options.theme.bar.buttons.style.bind("value"), networkLabel.bind("value")], (style, showLabel) => {
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
- return `network ${styleMap[style]}${!showLabel ? " no-label" : ""}`;
- }),
+ className: Utils.merge(
+ [options.theme.bar.buttons.style.bind('value'), networkLabel.bind('value')],
+ (style, showLabel) => {
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `network ${styleMap[style]}${!showLabel ? ' no-label' : ''}`;
+ },
+ ),
children: [
Widget.Icon({
- class_name: "bar-button-icon network",
- icon: Utils.merge([
- network.bind("primary"),
- network.bind("wifi"),
- network.bind("wired")
- ], (pmry, wfi, wrd) => {
- if (pmry === "wired") {
- return wrd.icon_name;
- }
- return wfi.icon_name;
- })
+ class_name: 'bar-button-icon network',
+ icon: Utils.merge(
+ [network.bind('primary'), network.bind('wifi'), network.bind('wired')],
+ (pmry, wfi, wrd) => {
+ if (pmry === 'wired') {
+ return wrd.icon_name;
+ }
+ return wfi.icon_name;
+ },
+ ),
}),
Widget.Box({
- vpack: "center",
- child: Utils.merge([
- network.bind("primary"),
- network.bind("wifi"),
- networkLabel.bind("value"),
- truncation.bind("value"),
- truncation_size.bind("value")
- ], (pmry, wfi, showLbl, trunc, tSize) => {
- if (!showLbl) {
- return Widget.Box();
- }
- if (pmry === "wired") {
+ vpack: 'center',
+ child: Utils.merge(
+ [
+ network.bind('primary'),
+ network.bind('wifi'),
+ networkLabel.bind('value'),
+ truncation.bind('value'),
+ truncation_size.bind('value'),
+ ],
+ (pmry, wfi, showLbl, trunc, tSize) => {
+ if (!showLbl) {
+ return Widget.Box();
+ }
+ if (pmry === 'wired') {
+ return Widget.Label({
+ class_name: 'bar-button-label network',
+ label: 'Wired'.substring(0, tSize),
+ });
+ }
return Widget.Label({
- class_name: "bar-button-label network",
- label: "Wired".substring(0, tSize),
- })
- }
- return Widget.Label({
- class_name: "bar-button-label network",
- label: wfi.ssid ? `${trunc ? wfi.ssid.substring(0, tSize) : wfi.ssid}` : "--",
- })
-
- })
+ class_name: 'bar-button-label network',
+ label: wfi.ssid ? `${trunc ? wfi.ssid.substring(0, tSize) : wfi.ssid}` : '--',
+ });
+ },
+ ),
}),
- ]
+ ],
}),
isVisible: true,
- boxClass: "network",
+ boxClass: 'network',
props: {
- on_primary_click: (clicked: any, event: Gdk.Event) => {
- openMenu(clicked, event, "networkmenu");
+ on_primary_click: (clicked: Button, event: Gdk.Event): void => {
+ openMenu(clicked, event, 'networkmenu');
},
},
};
diff --git a/modules/bar/notifications/index.ts b/modules/bar/notifications/index.ts
index f168a4e..4a29de4 100644
--- a/modules/bar/notifications/index.ts
+++ b/modules/bar/notifications/index.ts
@@ -1,39 +1,50 @@
import Gdk from 'gi://Gdk?version=3.0';
-import { openMenu } from "../utils.js";
-import options from "options";
+import { openMenu } from '../utils.js';
+import options from 'options';
+import { filterNotifications } from 'lib/shared/notifications.js';
+import { BarBoxChild } from 'lib/types/bar.js';
+import Button from 'types/widgets/button.js';
+import { Child } from 'lib/types/widget.js';
const { show_total } = options.bar.notifications;
+const { ignore } = options.notifications;
-const notifs = await Service.import("notifications");
+const notifs = await Service.import('notifications');
-export const Notifications = () => {
+export const Notifications = (): BarBoxChild => {
return {
component: Widget.Box({
- hpack: "start",
- className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_total.bind("value")], (style, showTotal) => {
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
- return `notifications ${styleMap[style]} ${!showTotal ? "no-label" : ""}`;
- }),
+ hpack: 'start',
+ className: Utils.merge(
+ [options.theme.bar.buttons.style.bind('value'), show_total.bind('value')],
+ (style, showTotal) => {
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `notifications ${styleMap[style]} ${!showTotal ? 'no-label' : ''}`;
+ },
+ ),
child: Widget.Box({
- hpack: "start",
- class_name: "bar-notifications",
+ hpack: 'start',
+ class_name: 'bar-notifications',
children: Utils.merge(
- [notifs.bind("notifications"), notifs.bind("dnd"), show_total.bind("value")],
- (notif, dnd, showTotal) => {
+ [notifs.bind('notifications'), notifs.bind('dnd'), show_total.bind('value'), ignore.bind('value')],
+ (notif, dnd, showTotal, ignoredNotifs) => {
+ const filteredNotifications = filterNotifications(notif, ignoredNotifs);
+
const notifIcon = Widget.Label({
- hpack: "center",
- class_name: "bar-button-icon notifications txt-icon bar",
- label: dnd ? "" : notif.length > 0 ? "" : "",
+ hpack: 'center',
+ class_name: 'bar-button-icon notifications txt-icon bar',
+ label: dnd ? '' : filteredNotifications.length > 0 ? '' : '',
});
const notifLabel = Widget.Label({
- hpack: "center",
- class_name: "bar-button-label notifications",
- label: notif.length.toString(),
+ hpack: 'center',
+ class_name: 'bar-button-label notifications',
+ label: filteredNotifications.length.toString(),
});
if (showTotal) {
@@ -45,10 +56,10 @@ export const Notifications = () => {
}),
}),
isVisible: true,
- boxClass: "notifications",
+ boxClass: 'notifications',
props: {
- on_primary_click: (clicked: any, event: Gdk.Event) => {
- openMenu(clicked, event, "notificationsmenu");
+ on_primary_click: (clicked: Button, event: Gdk.Event): void => {
+ openMenu(clicked, event, 'notificationsmenu');
},
},
};
diff --git a/modules/bar/systray/index.ts b/modules/bar/systray/index.ts
index 1d4cc0e..0f204c1 100644
--- a/modules/bar/systray/index.ts
+++ b/modules/bar/systray/index.ts
@@ -1,47 +1,43 @@
import Gdk from 'gi://Gdk?version=3.0';
-const systemtray = await Service.import("systemtray");
-import options from "options";
+import { BarBoxChild, SelfButton } from 'lib/types/bar';
+import { Notify } from 'lib/utils';
+const systemtray = await Service.import('systemtray');
+import options from 'options';
const { ignore } = options.bar.systray;
-const SysTray = () => {
+const SysTray = (): BarBoxChild => {
const isVis = Variable(false);
- const items = Utils.merge(
- [systemtray.bind("items"), ignore.bind("value")],
- (items, ignored) => {
- const filteredTray = items.filter(({ id }) => !ignored.includes(id));
+ const items = Utils.merge([systemtray.bind('items'), ignore.bind('value')], (items, ignored) => {
+ const filteredTray = items.filter(({ id }) => !ignored.includes(id));
- isVis.value = filteredTray.length > 0;
+ isVis.value = filteredTray.length > 0;
- return filteredTray.map((item) => {
- if (item.menu !== undefined) {
- item.menu["class_name"] = "systray-menu";
- }
-
- return Widget.Button({
- cursor: "pointer",
- child: Widget.Icon({
- class_name: "systray-icon",
- icon: item.bind("icon"),
- }),
- on_primary_click: (_: any, event: Gdk.Event) => item.activate(event),
- on_secondary_click: (_, event) => item.openMenu(event),
- tooltip_markup: item.bind("tooltip_markup"),
- });
+ return filteredTray.map((item) => {
+ return Widget.Button({
+ cursor: 'pointer',
+ child: Widget.Icon({
+ class_name: 'systray-icon',
+ icon: item.bind('icon'),
+ }),
+ on_primary_click: (_: SelfButton, event: Gdk.Event) => item.activate(event),
+ on_secondary_click: (_, event) => item.openMenu(event),
+ onMiddleClick: () => Notify({ summary: 'App Name', body: item.id }),
+ tooltip_markup: item.bind('tooltip_markup'),
});
- },
- );
+ });
+ });
return {
component: Widget.Box({
- class_name: "systray",
+ class_name: 'systray',
children: items,
}),
isVisible: true,
- boxClass: "systray",
+ boxClass: 'systray',
isVis,
- props: {}
+ props: {},
};
};
diff --git a/modules/bar/utils.ts b/modules/bar/utils.ts
index c8ee55e..660af79 100644
--- a/modules/bar/utils.ts
+++ b/modules/bar/utils.ts
@@ -1,6 +1,8 @@
import Gdk from 'gi://Gdk?version=3.0';
+import { Child } from 'lib/types/widget';
+import Button from 'types/widgets/button';
-export const closeAllMenus = () => {
+export const closeAllMenus = (): void => {
const menuWindows = App.windows
.filter((w) => {
if (w.name) {
@@ -18,7 +20,7 @@ export const closeAllMenus = () => {
});
};
-export const openMenu = (clicked: any, event: Gdk.Event, window: string) => {
+export const openMenu = (clicked: Button, event: Gdk.Event, window: string): void => {
/*
* NOTE: We have to make some adjustments so the menu pops up relatively
* to the center of the button clicked. We don't want the menu to spawn
diff --git a/modules/bar/volume/index.ts b/modules/bar/volume/index.ts
index 4c62062..64e76b8 100644
--- a/modules/bar/volume/index.ts
+++ b/modules/bar/volume/index.ts
@@ -1,56 +1,71 @@
import Gdk from 'gi://Gdk?version=3.0';
-const audio = await Service.import("audio");
-import { openMenu } from "../utils.js";
-import options from "options";
+const audio = await Service.import('audio');
+import { openMenu } from '../utils.js';
+import options from 'options';
+import { Binding } from 'lib/utils.js';
+import { VolumeIcons } from 'lib/types/volume.js';
+import { BarBoxChild } from 'lib/types/bar.js';
+import { Bind } from 'lib/types/variable.js';
+import Button from 'types/widgets/button.js';
+import { Child } from 'lib/types/widget.js';
-const Volume = () => {
- const icons = {
- 101: "",
- 66: "",
- 34: "",
- 1: "",
- 0: "",
+const Volume = (): BarBoxChild => {
+ const icons: VolumeIcons = {
+ 101: '',
+ 66: '',
+ 34: '',
+ 1: '',
+ 0: '',
};
- const getIcon = () => {
- const icon = Utils.merge(
- [audio.speaker.bind("is_muted"), audio.speaker.bind("volume")],
+ const getIcon = (): Bind => {
+ const icon: Binding = Utils.merge(
+ [audio.speaker.bind('is_muted'), audio.speaker.bind('volume')],
(isMuted, vol) => {
- return isMuted
- ? 0
- : [101, 66, 34, 1, 0].find((threshold) => threshold <= vol * 100);
+ if (isMuted) return 0;
+
+ const foundVol = [101, 66, 34, 1, 0].find((threshold) => threshold <= vol * 100);
+
+ if (foundVol !== undefined) {
+ return foundVol;
+ }
+
+ return 101;
},
);
- return icon.as((i) => i !== undefined ? icons[i] : 101);
+ return icon.as((i: number) => (i !== undefined ? icons[i] : icons[101]));
};
const volIcn = Widget.Label({
hexpand: true,
label: getIcon(),
- class_name: "bar-button-icon volume txt-icon bar",
+ class_name: 'bar-button-icon volume txt-icon bar',
});
const volPct = Widget.Label({
hexpand: true,
- label: audio.speaker.bind("volume").as((v) => `${Math.round(v * 100)}%`),
- class_name: "bar-button-label volume",
+ label: audio.speaker.bind('volume').as((v) => `${Math.round(v * 100)}%`),
+ class_name: 'bar-button-label volume',
});
return {
component: Widget.Box({
hexpand: true,
vexpand: true,
- className: Utils.merge([options.theme.bar.buttons.style.bind("value"), options.bar.volume.label.bind("value")], (style, showLabel) => {
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
-
- return `volume ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
- }),
- children: options.bar.volume.label.bind("value").as((showLabel) => {
+ className: Utils.merge(
+ [options.theme.bar.buttons.style.bind('value'), options.bar.volume.label.bind('value')],
+ (style, showLabel) => {
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `volume ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
+ },
+ ),
+ children: options.bar.volume.label.bind('value').as((showLabel) => {
if (showLabel) {
return [volIcn, volPct];
}
@@ -58,10 +73,10 @@ const Volume = () => {
}),
}),
isVisible: true,
- boxClass: "volume",
+ boxClass: 'volume',
props: {
- on_primary_click: (clicked: any, event: Gdk.Event) => {
- openMenu(clicked, event, "audiomenu");
+ on_primary_click: (clicked: Button, event: Gdk.Event): void => {
+ openMenu(clicked, event, 'audiomenu');
},
},
};
diff --git a/modules/bar/window_title/index.ts b/modules/bar/window_title/index.ts
index 58a887c..07856d6 100644
--- a/modules/bar/window_title/index.ts
+++ b/modules/bar/window_title/index.ts
@@ -1,121 +1,119 @@
-const hyprland = await Service.import("hyprland");
+const hyprland = await Service.import('hyprland');
+import { BarBoxChild } from 'lib/types/bar';
import options from 'options';
-import { ActiveClient } from 'types/service/hyprland'
+import { ActiveClient } from 'types/service/hyprland';
-const filterTitle = (windowtitle: ActiveClient) => {
+const filterTitle = (windowtitle: ActiveClient): Record => {
const windowTitleMap = [
// user provided values
...options.bar.windowtitle.title_map.value,
// Original Entries
- ["kitty", "", "Kitty Terminal"],
- ["firefox", "", "Firefox"],
- ["microsoft-edge", "", "Edge"],
- ["discord", "", "Discord"],
- ["vesktop", "", "Vesktop"],
- ["org.kde.dolphin", "", "Dolphin"],
- ["plex", "", "Plex"],
- ["steam", "", "Steam"],
- ["spotify", "", "Spotify"],
- ["ristretto", "", "Ristretto"],
- ["obsidian", "", "Obsidian"],
+ ['kitty', '', 'Kitty Terminal'],
+ ['firefox', '', 'Firefox'],
+ ['microsoft-edge', '', 'Edge'],
+ ['discord', '', 'Discord'],
+ ['vesktop', '', 'Vesktop'],
+ ['org.kde.dolphin', '', 'Dolphin'],
+ ['plex', '', 'Plex'],
+ ['steam', '', 'Steam'],
+ ['spotify', '', 'Spotify'],
+ ['ristretto', '', 'Ristretto'],
+ ['obsidian', '', 'Obsidian'],
// Browsers
- ["google-chrome", "", "Google Chrome"],
- ["brave-browser", "", "Brave Browser"],
- ["chromium", "", "Chromium"],
- ["opera", "", "Opera"],
- ["vivaldi", "", "Vivaldi"],
- ["waterfox", "", "Waterfox"],
- ["thorium", "", "Waterfox"],
- ["tor-browser", "", "Tor Browser"],
- ["floorp", "", "Floorp"],
+ ['google-chrome', '', 'Google Chrome'],
+ ['brave-browser', '', 'Brave Browser'],
+ ['chromium', '', 'Chromium'],
+ ['opera', '', 'Opera'],
+ ['vivaldi', '', 'Vivaldi'],
+ ['waterfox', '', 'Waterfox'],
+ ['thorium', '', 'Waterfox'],
+ ['tor-browser', '', 'Tor Browser'],
+ ['floorp', '', 'Floorp'],
// Terminals
- ["gnome-terminal", "", "GNOME Terminal"],
- ["konsole", "", "Konsole"],
- ["alacritty", "", "Alacritty"],
- ["wezterm", "", "Wezterm"],
- ["foot", "", "Foot Terminal"],
- ["tilix", "", "Tilix"],
- ["xterm", "", "XTerm"],
- ["urxvt", "", "URxvt"],
- ["st", "", "st Terminal"],
+ ['gnome-terminal', '', 'GNOME Terminal'],
+ ['konsole', '', 'Konsole'],
+ ['alacritty', '', 'Alacritty'],
+ ['wezterm', '', 'Wezterm'],
+ ['foot', '', 'Foot Terminal'],
+ ['tilix', '', 'Tilix'],
+ ['xterm', '', 'XTerm'],
+ ['urxvt', '', 'URxvt'],
+ ['st', '', 'st Terminal'],
// Development Tools
- ["code", "", "Visual Studio Code"],
- ["vscode", "", "VS Code"],
- ["sublime-text", "", "Sublime Text"],
- ["atom", "", "Atom"],
- ["android-studio", "", "Android Studio"],
- ["intellij-idea", "", "IntelliJ IDEA"],
- ["pycharm", "", "PyCharm"],
- ["webstorm", "", "WebStorm"],
- ["phpstorm", "", "PhpStorm"],
- ["eclipse", "", "Eclipse"],
- ["netbeans", "", "NetBeans"],
- ["docker", "", "Docker"],
- ["vim", "", "Vim"],
- ["neovim", "", "Neovim"],
- ["neovide", "", "Neovide"],
- ["emacs", "", "Emacs"],
+ ['code', '', 'Visual Studio Code'],
+ ['vscode', '', 'VS Code'],
+ ['sublime-text', '', 'Sublime Text'],
+ ['atom', '', 'Atom'],
+ ['android-studio', '', 'Android Studio'],
+ ['intellij-idea', '', 'IntelliJ IDEA'],
+ ['pycharm', '', 'PyCharm'],
+ ['webstorm', '', 'WebStorm'],
+ ['phpstorm', '', 'PhpStorm'],
+ ['eclipse', '', 'Eclipse'],
+ ['netbeans', '', 'NetBeans'],
+ ['docker', '', 'Docker'],
+ ['vim', '', 'Vim'],
+ ['neovim', '', 'Neovim'],
+ ['neovide', '', 'Neovide'],
+ ['emacs', '', 'Emacs'],
// Communication Tools
- ["slack", "", "Slack"],
- ["telegram-desktop", "", "Telegram"],
- ["org.telegram.desktop", "", "Telegram"],
- ["whatsapp", "", "WhatsApp"],
- ["teams", "", "Microsoft Teams"],
- ["skype", "", "Skype"],
- ["thunderbird", "", "Thunderbird"],
+ ['slack', '', 'Slack'],
+ ['telegram-desktop', '', 'Telegram'],
+ ['org.telegram.desktop', '', 'Telegram'],
+ ['whatsapp', '', 'WhatsApp'],
+ ['teams', '', 'Microsoft Teams'],
+ ['skype', '', 'Skype'],
+ ['thunderbird', '', 'Thunderbird'],
// File Managers
- ["nautilus", "", "Files (Nautilus)"],
- ["thunar", "", "Thunar"],
- ["pcmanfm", "", "PCManFM"],
- ["nemo", "", "Nemo"],
- ["ranger", "", "Ranger"],
- ["doublecmd", "", "Double Commander"],
- ["krusader", "", "Krusader"],
+ ['nautilus', '', 'Files (Nautilus)'],
+ ['thunar', '', 'Thunar'],
+ ['pcmanfm', '', 'PCManFM'],
+ ['nemo', '', 'Nemo'],
+ ['ranger', '', 'Ranger'],
+ ['doublecmd', '', 'Double Commander'],
+ ['krusader', '', 'Krusader'],
// Media Players
- ["vlc", "", "VLC Media Player"],
- ["mpv", "", "MPV"],
- ["rhythmbox", "", "Rhythmbox"],
+ ['vlc', '', 'VLC Media Player'],
+ ['mpv', '', 'MPV'],
+ ['rhythmbox', '', 'Rhythmbox'],
// Graphics Tools
- ["gimp", "", "GIMP"],
- ["inkscape", "", "Inkscape"],
- ["krita", "", "Krita"],
- ["blender", "", "Blender"],
+ ['gimp', '', 'GIMP'],
+ ['inkscape', '', 'Inkscape'],
+ ['krita', '', 'Krita'],
+ ['blender', '', 'Blender'],
// Video Editing
- ["kdenlive", "", "Kdenlive"],
+ ['kdenlive', '', 'Kdenlive'],
// Games and Gaming Platforms
- ["lutris", "", "Lutris"],
- ["heroic", "", "Heroic Games Launcher"],
- ["minecraft", "", "Minecraft"],
- ["csgo", "", "CS:GO"],
- ["dota2", "", "Dota 2"],
+ ['lutris', '', 'Lutris'],
+ ['heroic', '', 'Heroic Games Launcher'],
+ ['minecraft', '', 'Minecraft'],
+ ['csgo', '', 'CS:GO'],
+ ['dota2', '', 'Dota 2'],
// Office and Productivity
- ["evernote", "", "Evernote"],
- ["sioyek", "", "Sioyek"],
-
+ ['evernote', '', 'Evernote'],
+ ['sioyek', '', 'Sioyek'],
// Cloud Services and Sync
- ["dropbox", "", "Dropbox"],
+ ['dropbox', '', 'Dropbox'],
// Desktop
- ["^$", "", "Desktop"],
+ ['^$', '', 'Desktop'],
// Fallback icon
- ["(.+)", "", `${windowtitle.class.charAt(0).toUpperCase() + windowtitle.class.slice(1)}`],
+ ['(.+)', '', `${windowtitle.class.charAt(0).toUpperCase() + windowtitle.class.slice(1)}`],
];
- const foundMatch = windowTitleMap.find((wt) =>
- RegExp(wt[0]).test(windowtitle.class.toLowerCase()),
- );
+ const foundMatch = windowTitleMap.find((wt) => RegExp(wt[0]).test(windowtitle.class.toLowerCase()));
// return the default icon if no match is found or
// if the array element matched is not of size 3
@@ -127,37 +125,93 @@ const filterTitle = (windowtitle: ActiveClient) => {
}
return {
- icon: foundMatch ? foundMatch[1] : windowTitleMap[windowTitleMap.length - 1][1],
- label: foundMatch ? foundMatch[2] : windowTitleMap[windowTitleMap.length - 1][2]
+ icon: foundMatch[1],
+ label: foundMatch[2],
};
};
-const ClientTitle = () => {
+const getTitle = (client: ActiveClient, useCustomTitle: boolean, useClassName: boolean): string => {
+ if (useCustomTitle) return filterTitle(client).label;
+ if (useClassName) return client.class;
+
+ const title = client.title;
+ // If the title is empty or only filled with spaces, fallback to the class name
+ if (title.length === 0 || title.match(/^ *$/)) {
+ return client.class;
+ }
+ return title;
+};
+
+const truncateTitle = (title: string, max_size: number): string => {
+ if (max_size > 0 && title.length > max_size) {
+ return title.substring(0, max_size).trim() + '...';
+ }
+ return title;
+};
+
+const ClientTitle = (): BarBoxChild => {
+ const { custom_title, class_name, label, icon, truncation, truncation_size } = options.bar.windowtitle;
+
return {
component: Widget.Box({
- className: Utils.merge([options.theme.bar.buttons.style.bind("value"), options.bar.windowtitle.label.bind("value")], (style, showLabel) => {
- const styleMap = {
- default: "style1",
- split: "style2",
- wave: "style3",
- };
- return `windowtitle ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
- }),
- children: options.bar.windowtitle.label.bind("value").as((showLabel) => {
- const titleIcon = Widget.Label({
- class_name: "bar-button-icon windowtitle txt-icon bar",
- label: hyprland.active.bind("client").as((v) => filterTitle(v).icon),
- });
- const titleLabel = Widget.Label({
- class_name: "bar-button-label windowtitle",
- label: hyprland.active.bind("client").as((v) => filterTitle(v).label),
- });
- return showLabel ? [titleIcon, titleLabel] : [titleIcon];
- }),
+ className: Utils.merge(
+ [options.theme.bar.buttons.style.bind('value'), label.bind('value')],
+ (style, showLabel) => {
+ const styleMap = {
+ default: 'style1',
+ split: 'style2',
+ wave: 'style3',
+ wave2: 'style3',
+ };
+ return `windowtitle ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
+ },
+ ),
+ children: Utils.merge(
+ [
+ hyprland.active.bind('client'),
+ custom_title.bind('value'),
+ class_name.bind('value'),
+ label.bind('value'),
+ icon.bind('value'),
+ truncation.bind('value'),
+ truncation_size.bind('value'),
+ ],
+ (client, useCustomTitle, useClassName, showLabel, showIcon, truncate, truncationSize) => {
+ if (showIcon) {
+ return [
+ Widget.Label({
+ class_name: 'bar-button-icon windowtitle txt-icon bar',
+ label: filterTitle(client).icon,
+ }),
+ Widget.Label({
+ class_name: `bar-button-label windowtitle ${showIcon ? '' : 'no-icon'}`,
+ label: truncateTitle(
+ getTitle(client, useCustomTitle, useClassName),
+ truncate ? truncationSize : -1,
+ ),
+ }),
+ ];
+ }
+
+ if (showLabel) {
+ return [
+ Widget.Label({
+ class_name: `bar-button-label windowtitle ${showIcon ? '' : 'no-icon'}`,
+ label: truncateTitle(
+ getTitle(client, useCustomTitle, useClassName),
+ truncate ? truncationSize : -1,
+ ),
+ }),
+ ];
+ }
+
+ return [];
+ },
+ ),
}),
isVisible: true,
- boxClass: "windowtitle",
- props: {}
+ boxClass: 'windowtitle',
+ props: {},
};
};
diff --git a/modules/bar/workspaces/helpers.ts b/modules/bar/workspaces/helpers.ts
index 1fbd45f..26d6d9c 100644
--- a/modules/bar/workspaces/helpers.ts
+++ b/modules/bar/workspaces/helpers.ts
@@ -1,23 +1,21 @@
-const hyprland = await Service.import("hyprland");
+const hyprland = await Service.import('hyprland');
-import { WorkspaceMap, WorkspaceRule } from "lib/types/workspace";
-import options from "options";
-import { Variable } from "types/variable";
-
-const {
- workspaces,
- reverse_scroll,
-} = options.bar.workspaces;
+import { MonitorMap, WorkspaceMap, WorkspaceRule } from 'lib/types/workspace';
+import options from 'options';
+import { Variable } from 'types/variable';
+const { workspaces, reverse_scroll } = options.bar.workspaces;
export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, monitor: number): boolean => {
if (!wsRules || !Object.keys(wsRules).length) {
return true;
}
- const monitorMap = {};
- const workspaceMonitorList = hyprland?.workspaces?.map(m => ({ id: m.monitorID, name: m.monitor }));
- const monitors = [...new Map([...workspaceMonitorList, ...hyprland.monitors].map(item => [item.id, item])).values()];
+ const monitorMap: MonitorMap = {};
+ const workspaceMonitorList = hyprland?.workspaces?.map((m) => ({ id: m.monitorID, name: m.monitor }));
+ const monitors = [
+ ...new Map([...workspaceMonitorList, ...hyprland.monitors].map((item) => [item.id, item])).values(),
+ ];
monitors.forEach((m) => (monitorMap[m.id] = m.name));
@@ -32,9 +30,9 @@ export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, mo
export const getWorkspaceRules = (): WorkspaceMap => {
try {
- const rules = Utils.exec("hyprctl workspacerules -j");
+ const rules = Utils.exec('hyprctl workspacerules -j');
- const workspaceRules = {};
+ const workspaceRules: WorkspaceMap = {};
JSON.parse(rules).forEach((rule: WorkspaceRule, index: number) => {
if (Object.hasOwnProperty.call(workspaceRules, rule.monitor)) {
@@ -60,13 +58,13 @@ export const getCurrentMonitorWorkspaces = (monitor: number): number[] => {
}
const monitorWorkspaces = getWorkspaceRules();
- const monitorMap = {};
+ const monitorMap: MonitorMap = {};
hyprland.monitors.forEach((m) => (monitorMap[m.id] = m.name));
const currentMonitorName = monitorMap[monitor];
return monitorWorkspaces[currentMonitorName];
-}
+};
export const goToNextWS = (currentMonitorWorkspaces: Variable, activeWorkspaces: boolean): void => {
if (activeWorkspaces === true) {
@@ -74,18 +72,17 @@ export const goToNextWS = (currentMonitorWorkspaces: Variable, activeW
let nextIndex = hyprland.active.workspace.id + 1;
if (nextIndex > activeWses[activeWses.length - 1].id) {
-
nextIndex = activeWses[0].id;
}
- hyprland.messageAsync(`dispatch workspace ${nextIndex}`)
+ hyprland.messageAsync(`dispatch workspace ${nextIndex}`);
} else if (currentMonitorWorkspaces.value === undefined) {
let nextIndex = hyprland.active.workspace.id + 1;
if (nextIndex > workspaces.value) {
nextIndex = 0;
}
- hyprland.messageAsync(`dispatch workspace ${nextIndex}`)
+ hyprland.messageAsync(`dispatch workspace ${nextIndex}`);
} else {
const curWorkspace = hyprland.active.workspace.id;
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
@@ -94,9 +91,9 @@ export const goToNextWS = (currentMonitorWorkspaces: Variable, activeW
nextIndex = 0;
}
- hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[nextIndex]}`)
+ hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[nextIndex]}`);
}
-}
+};
export const goToPrevWS = (currentMonitorWorkspaces: Variable, activeWorkspaces: boolean): void => {
if (activeWorkspaces === true) {
@@ -104,11 +101,10 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable, activeW
let prevIndex = hyprland.active.workspace.id - 1;
if (prevIndex < activeWses[0].id) {
-
prevIndex = activeWses[activeWses.length - 1].id;
}
- hyprland.messageAsync(`dispatch workspace ${prevIndex}`)
+ hyprland.messageAsync(`dispatch workspace ${prevIndex}`);
} else if (currentMonitorWorkspaces.value === undefined) {
let prevIndex = hyprland.active.workspace.id - 1;
@@ -116,7 +112,7 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable, activeW
prevIndex = workspaces.value;
}
- hyprland.messageAsync(`dispatch workspace ${prevIndex}`)
+ hyprland.messageAsync(`dispatch workspace ${prevIndex}`);
} else {
const curWorkspace = hyprland.active.workspace.id;
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
@@ -125,11 +121,11 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable, activeW
prevIndex = currentMonitorWorkspaces.value.length - 1;
}
- hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[prevIndex]}`)
+ hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[prevIndex]}`);
}
-}
+};
-export function throttle void>(func: T, limit: number): T {
+export function throttle void>(func: T, limit: number): T {
let inThrottle: boolean;
return function (this: ThisParameterType, ...args: Parameters) {
if (!inThrottle) {
@@ -147,7 +143,11 @@ type ThrottledScrollHandlers = {
throttledScrollDown: () => void;
};
-export const createThrottledScrollHandlers = (scrollSpeed: number, currentMonitorWorkspaces: Variable, activeWorkspaces: boolean = false): ThrottledScrollHandlers => {
+export const createThrottledScrollHandlers = (
+ scrollSpeed: number,
+ currentMonitorWorkspaces: Variable,
+ activeWorkspaces: boolean = false,
+): ThrottledScrollHandlers => {
const throttledScrollUp = throttle(() => {
if (reverse_scroll.value === true) {
goToPrevWS(currentMonitorWorkspaces, activeWorkspaces);
@@ -165,4 +165,4 @@ export const createThrottledScrollHandlers = (scrollSpeed: number, currentMonito
}, 200 / scrollSpeed);
return { throttledScrollUp, throttledScrollDown };
-}
+};
diff --git a/modules/bar/workspaces/index.ts b/modules/bar/workspaces/index.ts
index c73e157..161d292 100644
--- a/modules/bar/workspaces/index.ts
+++ b/modules/bar/workspaces/index.ts
@@ -1,271 +1,43 @@
-const hyprland = await Service.import("hyprland");
-import options from "options";
-import { createThrottledScrollHandlers, getCurrentMonitorWorkspaces, getWorkspaceRules, getWorkspacesForMonitor } from "./helpers";
-import { Workspace } from "types/service/hyprland";
+import options from 'options';
+import { createThrottledScrollHandlers, getCurrentMonitorWorkspaces } from './helpers';
+import { BarBoxChild, SelfButton } from 'lib/types/bar';
+import { occupiedWses } from './variants/occupied';
+import { defaultWses } from './variants/default';
-const {
- workspaces,
- monitorSpecific,
- workspaceMask,
- scroll_speed,
- spacing
-} = options.bar.workspaces;
+const { workspaces, scroll_speed } = options.bar.workspaces;
-function range(length: number, start = 1) {
- return Array.from({ length }, (_, i) => i + start);
-}
-
-const Workspaces = (monitor = -1) => {
+const Workspaces = (monitor = -1): BarBoxChild => {
const currentMonitorWorkspaces = Variable(getCurrentMonitorWorkspaces(monitor));
- workspaces.connect("changed", () => {
- currentMonitorWorkspaces.value = getCurrentMonitorWorkspaces(monitor)
- })
-
- const renderClassnames = (showIcons: boolean, showNumbered: boolean, numberedActiveIndicator: string, i: number) => {
- 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";
- }
-
- const renderLabel = (showIcons: boolean, available: string, active: string, occupied: string, workspaceMask: boolean, i: number, index: number) => {
- 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}`;
- }
- const defaultWses = () => {
- 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, _: number) => {
- 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,
- );
- });
- },
- })
- });
- });
- },
- )
- })
- }
- const occupiedWses = () => {
- 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),
- setup: (self) => {
- self.toggleClassName(
- "active",
- activeId === i,
- );
- self.toggleClassName(
- "occupied",
- (hyprland.getWorkspace(i)?.windows || 0) > 0,
- );
- },
- })
- });
- });
- },
- )
- })
- }
+ workspaces.connect('changed', () => {
+ currentMonitorWorkspaces.value = getCurrentMonitorWorkspaces(monitor);
+ });
return {
component: Widget.Box({
- class_name: "workspaces",
- child: options.bar.workspaces.hideUnoccupied.bind("value").as(hideUnoccupied => hideUnoccupied ? occupiedWses() : defaultWses()),
+ class_name: 'workspaces',
+ child: options.bar.workspaces.hideUnoccupied
+ .bind('value')
+ .as((hideUnoccupied) => (hideUnoccupied ? occupiedWses(monitor) : defaultWses(monitor))),
}),
isVisible: true,
- boxClass: "workspaces",
+ boxClass: 'workspaces',
props: {
- setup: (self: any) => {
- Utils.merge([scroll_speed.bind("value"), options.bar.workspaces.hideUnoccupied.bind("value")], (scroll_speed, hideUnoccupied) => {
- const { throttledScrollUp, throttledScrollDown } = createThrottledScrollHandlers(scroll_speed, currentMonitorWorkspaces, hideUnoccupied)
- self.on_scroll_up = throttledScrollUp;
- self.on_scroll_down = throttledScrollDown;
- });
- }
- }
+ setup: (self: SelfButton): void => {
+ Utils.merge(
+ [scroll_speed.bind('value'), options.bar.workspaces.hideUnoccupied.bind('value')],
+ (scroll_speed, hideUnoccupied) => {
+ const { throttledScrollUp, throttledScrollDown } = createThrottledScrollHandlers(
+ scroll_speed,
+ currentMonitorWorkspaces,
+ hideUnoccupied,
+ );
+ self.on_scroll_up = throttledScrollUp;
+ self.on_scroll_down = throttledScrollDown;
+ },
+ );
+ },
+ },
};
};
diff --git a/modules/bar/workspaces/utils.ts b/modules/bar/workspaces/utils.ts
new file mode 100644
index 0000000..ed29582
--- /dev/null
+++ b/modules/bar/workspaces/utils.ts
@@ -0,0 +1,89 @@
+import { WorkspaceIconMap } from 'lib/types/workspace';
+import { isValidGjsColor } from 'lib/utils';
+
+const hyprland = await Service.import('hyprland');
+
+const getWsIcon = (wsIconMap: WorkspaceIconMap, i: number): string => {
+ const iconEntry = wsIconMap[i];
+
+ if (!iconEntry) {
+ return `${i}`;
+ }
+
+ const hasIcon = typeof iconEntry === 'object' && 'icon' in iconEntry && iconEntry.icon !== '';
+
+ if (typeof iconEntry === 'string' && iconEntry !== '') {
+ return iconEntry;
+ }
+
+ if (hasIcon) {
+ return iconEntry.icon;
+ }
+
+ return `${i}`;
+};
+
+export const getWsColor = (wsIconMap: WorkspaceIconMap, i: number): string => {
+ const iconEntry = wsIconMap[i];
+ if (!iconEntry) {
+ return '';
+ }
+
+ const hasColor = typeof iconEntry === 'object' && 'color' in iconEntry && iconEntry.color !== '';
+ if (hasColor && isValidGjsColor(iconEntry.color)) {
+ return `color: ${iconEntry.color}; border-bottom-color: ${iconEntry.color};`;
+ }
+ return '';
+};
+
+export const renderClassnames = (
+ showIcons: boolean,
+ showNumbered: boolean,
+ numberedActiveIndicator: string,
+ showWsIcons: boolean,
+ i: number,
+): string => {
+ if (showIcons) {
+ return `workspace-icon txt-icon bar`;
+ }
+ if (showNumbered || showWsIcons) {
+ const numActiveInd = hyprland.active.workspace.id === i ? `${numberedActiveIndicator}` : '';
+
+ const className =
+ `workspace-number can_${numberedActiveIndicator} ` +
+ `${numActiveInd} ` +
+ `${showWsIcons ? 'txt-icon' : ''}`;
+
+ return className;
+ }
+ return 'default';
+};
+
+export const renderLabel = (
+ showIcons: boolean,
+ available: string,
+ active: string,
+ occupied: string,
+ workspaceMask: boolean,
+ showWsIcons: boolean,
+ wsIconMap: WorkspaceIconMap,
+ 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;
+ }
+ }
+ if (showWsIcons) {
+ return getWsIcon(wsIconMap, i);
+ }
+ return workspaceMask ? `${index + 1}` : `${i}`;
+};
diff --git a/modules/bar/workspaces/variants/default.ts b/modules/bar/workspaces/variants/default.ts
new file mode 100644
index 0000000..ccd985b
--- /dev/null
+++ b/modules/bar/workspaces/variants/default.ts
@@ -0,0 +1,125 @@
+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';
+import { getWsColor, renderClassnames, renderLabel } from '../utils';
+import { WorkspaceIconMap } from 'lib/types/workspace';
+
+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: Utils.merge(
+ [
+ spacing.bind('value'),
+ options.bar.workspaces.showWsIcons.bind('value'),
+ options.bar.workspaces.workspaceIconMap.bind('value'),
+ options.theme.matugen.bind('value'),
+ ],
+ (
+ sp: number,
+ showWsIcons: boolean,
+ workspaceIconMap: WorkspaceIconMap,
+ matugen: boolean,
+ ) => {
+ return (
+ `margin: 0rem ${0.375 * sp}rem;` +
+ `${showWsIcons && !matugen ? getWsColor(workspaceIconMap, i) : ''}`
+ );
+ },
+ ),
+ 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.showWsIcons.bind('value'),
+ options.bar.workspaces.icons.available.bind('value'),
+ options.bar.workspaces.icons.active.bind('value'),
+ hyprland.active.workspace.bind('id'),
+ ],
+ (
+ showIcons: boolean,
+ showNumbered: boolean,
+ numberedActiveIndicator: string,
+ showWsIcons: boolean,
+ ) => {
+ return renderClassnames(
+ showIcons,
+ showNumbered,
+ numberedActiveIndicator,
+ showWsIcons,
+ i,
+ );
+ },
+ ),
+ 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'),
+ options.bar.workspaces.workspaceIconMap.bind('value'),
+ options.bar.workspaces.showWsIcons.bind('value'),
+ workspaceMask.bind('value'),
+ hyprland.active.workspace.bind('id'),
+ ],
+ (
+ showIcons: boolean,
+ available: string,
+ active: string,
+ occupied: string,
+ wsIconMap: WorkspaceIconMap,
+ showWsIcons: boolean,
+ workspaceMask: boolean,
+ ) => {
+ return renderLabel(
+ showIcons,
+ available,
+ active,
+ occupied,
+ workspaceMask,
+ showWsIcons,
+ wsIconMap,
+ i,
+ index,
+ monitor,
+ );
+ },
+ ),
+ setup: (self) => {
+ self.hook(hyprland, () => {
+ self.toggleClassName('active', hyprland.active.workspace.id === i);
+ self.toggleClassName('occupied', (hyprland.getWorkspace(i)?.windows || 0) > 0);
+ });
+ },
+ }),
+ });
+ });
+ },
+ ),
+ });
+};
diff --git a/modules/bar/workspaces/variants/occupied.ts b/modules/bar/workspaces/variants/occupied.ts
new file mode 100644
index 0000000..028ec4a
--- /dev/null
+++ b/modules/bar/workspaces/variants/occupied.ts
@@ -0,0 +1,134 @@
+const hyprland = await Service.import('hyprland');
+import options from 'options';
+import { getWorkspaceRules, getWorkspacesForMonitor } from '../helpers';
+import { Workspace } from 'types/service/hyprland';
+import { getWsColor, renderClassnames, renderLabel } from '../utils';
+import { range } from 'lib/utils';
+import { BoxWidget } from 'lib/types/widget';
+import { WorkspaceIconMap } from 'lib/types/workspace';
+
+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'),
+ options.bar.workspaces.workspaceIconMap.bind('value'),
+ options.bar.workspaces.showWsIcons.bind('value'),
+ options.theme.matugen.bind('value'),
+ ],
+ (
+ monitorSpecific: boolean,
+ wkSpaces: Workspace[],
+ workspaceMask: boolean,
+ totalWkspcs: number,
+ showIcons: boolean,
+ available: string,
+ active: string,
+ occupied: string,
+ showNumbered: boolean,
+ numberedActiveIndicator: string,
+ spacing: number,
+ activeId: number,
+ wsIconMap: WorkspaceIconMap,
+ showWsIcons: boolean,
+ matugen: boolean,
+ ) => {
+ 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;` +
+ `${showWsIcons && !matugen ? getWsColor(wsIconMap, i) : ''}`,
+ class_name: renderClassnames(
+ showIcons,
+ showNumbered,
+ numberedActiveIndicator,
+ showWsIcons,
+ i,
+ ),
+ label: renderLabel(
+ showIcons,
+ available,
+ active,
+ occupied,
+ workspaceMask,
+ showWsIcons,
+ wsIconMap,
+ i,
+ index,
+ monitor,
+ ),
+ setup: (self) => {
+ self.toggleClassName('active', activeId === i);
+ self.toggleClassName('occupied', (hyprland.getWorkspace(i)?.windows || 0) > 0);
+ },
+ }),
+ });
+ });
+ },
+ ),
+ });
+};
diff --git a/modules/icons/index.ts b/modules/icons/index.ts
index a573875..14d0a06 100644
--- a/modules/icons/index.ts
+++ b/modules/icons/index.ts
@@ -1,199 +1,199 @@
export const substitutes = {
- "transmission-gtk": "transmission",
- "blueberry.py": "blueberry",
- Caprine: "facebook-messenger",
- "com.raggesilver.BlackBox-symbolic": "terminal-symbolic",
- "org.wezfurlong.wezterm-symbolic": "terminal-symbolic",
- "audio-headset-bluetooth": "audio-headphones-symbolic",
- "audio-card-analog-usb": "audio-speakers-symbolic",
- "audio-card-analog-pci": "audio-card-symbolic",
- "preferences-system": "emblem-system-symbolic",
- "com.github.Aylur.ags-symbolic": "controls-symbolic",
- "com.github.Aylur.ags": "controls-symbolic",
+ 'transmission-gtk': 'transmission',
+ 'blueberry.py': 'blueberry',
+ Caprine: 'facebook-messenger',
+ 'com.raggesilver.BlackBox-symbolic': 'terminal-symbolic',
+ 'org.wezfurlong.wezterm-symbolic': 'terminal-symbolic',
+ 'audio-headset-bluetooth': 'audio-headphones-symbolic',
+ 'audio-card-analog-usb': 'audio-speakers-symbolic',
+ 'audio-card-analog-pci': 'audio-card-symbolic',
+ 'preferences-system': 'emblem-system-symbolic',
+ 'com.github.Aylur.ags-symbolic': 'controls-symbolic',
+ 'com.github.Aylur.ags': 'controls-symbolic',
};
export default {
- missing: "image-missing-symbolic",
+ missing: 'image-missing-symbolic',
nix: {
- nix: "nix-snowflake-symbolic",
+ nix: 'nix-snowflake-symbolic',
},
app: {
- terminal: "terminal-symbolic",
+ terminal: 'terminal-symbolic',
},
fallback: {
- executable: "application-x-executable",
- notification: "dialog-information-symbolic",
- video: "video-x-generic-symbolic",
- audio: "audio-x-generic-symbolic",
+ executable: 'application-x-executable',
+ notification: 'dialog-information-symbolic',
+ video: 'video-x-generic-symbolic',
+ audio: 'audio-x-generic-symbolic',
},
ui: {
- close: "window-close-symbolic",
- colorpicker: "color-select-symbolic",
- info: "info-symbolic",
- link: "external-link-symbolic",
- lock: "system-lock-screen-symbolic",
- menu: "open-menu-symbolic",
- refresh: "view-refresh-symbolic",
- search: "system-search-symbolic",
- settings: "emblem-system-symbolic",
- themes: "preferences-desktop-theme-symbolic",
- tick: "object-select-symbolic",
- time: "hourglass-symbolic",
- toolbars: "toolbars-symbolic",
- warning: "dialog-warning-symbolic",
- avatar: "avatar-default-symbolic",
+ close: 'window-close-symbolic',
+ colorpicker: 'color-select-symbolic',
+ info: 'info-symbolic',
+ link: 'external-link-symbolic',
+ lock: 'system-lock-screen-symbolic',
+ menu: 'open-menu-symbolic',
+ refresh: 'view-refresh-symbolic',
+ search: 'system-search-symbolic',
+ settings: 'emblem-system-symbolic',
+ themes: 'preferences-desktop-theme-symbolic',
+ tick: 'object-select-symbolic',
+ time: 'hourglass-symbolic',
+ toolbars: 'toolbars-symbolic',
+ warning: 'dialog-warning-symbolic',
+ avatar: 'avatar-default-symbolic',
arrow: {
- right: "pan-end-symbolic",
- left: "pan-start-symbolic",
- down: "pan-down-symbolic",
- up: "pan-up-symbolic",
+ right: 'pan-end-symbolic',
+ left: 'pan-start-symbolic',
+ down: 'pan-down-symbolic',
+ up: 'pan-up-symbolic',
},
},
audio: {
mic: {
- muted: "microphone-disabled-symbolic",
- low: "microphone-sensitivity-low-symbolic",
- medium: "microphone-sensitivity-medium-symbolic",
- high: "microphone-sensitivity-high-symbolic",
+ muted: 'microphone-disabled-symbolic',
+ low: 'microphone-sensitivity-low-symbolic',
+ medium: 'microphone-sensitivity-medium-symbolic',
+ high: 'microphone-sensitivity-high-symbolic',
},
volume: {
- muted: "audio-volume-muted-symbolic",
- low: "audio-volume-low-symbolic",
- medium: "audio-volume-medium-symbolic",
- high: "audio-volume-high-symbolic",
- overamplified: "audio-volume-overamplified-symbolic",
+ muted: 'audio-volume-muted-symbolic',
+ low: 'audio-volume-low-symbolic',
+ medium: 'audio-volume-medium-symbolic',
+ high: 'audio-volume-high-symbolic',
+ overamplified: 'audio-volume-overamplified-symbolic',
},
type: {
- headset: "audio-headphones-symbolic",
- speaker: "audio-speakers-symbolic",
- card: "audio-card-symbolic",
+ headset: 'audio-headphones-symbolic',
+ speaker: 'audio-speakers-symbolic',
+ card: 'audio-card-symbolic',
},
- mixer: "mixer-symbolic",
+ mixer: 'mixer-symbolic',
},
powerprofile: {
- balanced: "power-profile-balanced-symbolic",
- "power-saver": "power-profile-power-saver-symbolic",
- performance: "power-profile-performance-symbolic",
+ balanced: 'power-profile-balanced-symbolic',
+ 'power-saver': 'power-profile-power-saver-symbolic',
+ performance: 'power-profile-performance-symbolic',
},
asusctl: {
profile: {
- Balanced: "power-profile-balanced-symbolic",
- Quiet: "power-profile-power-saver-symbolic",
- Performance: "power-profile-performance-symbolic",
+ Balanced: 'power-profile-balanced-symbolic',
+ Quiet: 'power-profile-power-saver-symbolic',
+ Performance: 'power-profile-performance-symbolic',
},
mode: {
- Integrated: "processor-symbolic",
- Hybrid: "controller-symbolic",
+ Integrated: 'processor-symbolic',
+ Hybrid: 'controller-symbolic',
},
},
battery: {
- charging: "battery-flash-symbolic",
- warning: "battery-empty-symbolic",
+ charging: 'battery-flash-symbolic',
+ warning: 'battery-empty-symbolic',
},
bluetooth: {
- enabled: "bluetooth-active-symbolic",
- disabled: "bluetooth-disabled-symbolic",
+ enabled: 'bluetooth-active-symbolic',
+ disabled: 'bluetooth-disabled-symbolic',
},
brightness: {
- indicator: "display-brightness-symbolic",
- keyboard: "keyboard-brightness-symbolic",
- screen: "display-brightness-symbolic",
+ indicator: 'display-brightness-symbolic',
+ keyboard: 'keyboard-brightness-symbolic',
+ screen: 'display-brightness-symbolic',
},
powermenu: {
- sleep: "weather-clear-night-symbolic",
- reboot: "system-reboot-symbolic",
- logout: "system-log-out-symbolic",
- shutdown: "system-shutdown-symbolic",
+ sleep: 'weather-clear-night-symbolic',
+ reboot: 'system-reboot-symbolic',
+ logout: 'system-log-out-symbolic',
+ shutdown: 'system-shutdown-symbolic',
},
recorder: {
- recording: "media-record-symbolic",
+ recording: 'media-record-symbolic',
},
notifications: {
- noisy: "org.gnome.Settings-notifications-symbolic",
- silent: "notifications-disabled-symbolic",
- message: "chat-bubbles-symbolic",
+ noisy: 'org.gnome.Settings-notifications-symbolic',
+ silent: 'notifications-disabled-symbolic',
+ message: 'chat-bubbles-symbolic',
},
trash: {
- full: "user-trash-full-symbolic",
- empty: "user-trash-symbolic",
+ full: 'user-trash-full-symbolic',
+ empty: 'user-trash-symbolic',
},
mpris: {
shuffle: {
- enabled: "media-playlist-shuffle-symbolic",
- disabled: "media-playlist-consecutive-symbolic",
+ enabled: 'media-playlist-shuffle-symbolic',
+ disabled: 'media-playlist-consecutive-symbolic',
},
loop: {
- none: "media-playlist-repeat-symbolic",
- track: "media-playlist-repeat-song-symbolic",
- playlist: "media-playlist-repeat-symbolic",
+ none: 'media-playlist-repeat-symbolic',
+ track: 'media-playlist-repeat-song-symbolic',
+ playlist: 'media-playlist-repeat-symbolic',
},
- playing: "media-playback-pause-symbolic",
- paused: "media-playback-start-symbolic",
- stopped: "media-playback-start-symbolic",
- prev: "media-skip-backward-symbolic",
- next: "media-skip-forward-symbolic",
+ playing: 'media-playback-pause-symbolic',
+ paused: 'media-playback-start-symbolic',
+ stopped: 'media-playback-start-symbolic',
+ prev: 'media-skip-backward-symbolic',
+ next: 'media-skip-forward-symbolic',
},
system: {
- cpu: "org.gnome.SystemMonitor-symbolic",
- ram: "drive-harddisk-solidstate-symbolic",
- temp: "temperature-symbolic",
+ cpu: 'org.gnome.SystemMonitor-symbolic',
+ ram: 'drive-harddisk-solidstate-symbolic',
+ temp: 'temperature-symbolic',
},
color: {
- dark: "dark-mode-symbolic",
- light: "light-mode-symbolic",
+ dark: 'dark-mode-symbolic',
+ light: 'light-mode-symbolic',
},
weather: {
- warning: "dialog-warning-symbolic",
- sunny: "weather-clear-symbolic",
- clear: "weather-clear-night-symbolic",
- partly_cloudy: "weather-few-clouds-symbolic",
- partly_cloudy_night: "weather-few-clouds-night-symbolic",
- cloudy: "weather-overcast-symbolic",
- overcast: "weather-overcast-symbolic",
- mist: "weather-overcast-symbolic",
- patchy_rain_nearby: "weather-showers-scattered-symbolic",
- patchy_rain_possible: "weather-showers-scattered-symbolic",
- patchy_snow_possible: "weather-snow-symbolic",
- patchy_sleet_possible: "weather-snow-symbolic",
- patchy_freezing_drizzle_possible: "weather-showers-scattered-symbolic",
- thundery_outbreaks_possible: "weather-overcast-symbolic",
- blowing_snow: "weather-snow-symbolic",
- blizzard: "weather-snow-symbolic",
- fog: "weather-fog-symbolic",
- freezing_fog: "weather-fog-symbolic",
- patchy_light_drizzle: "weather-showers-scattered-symbolic",
- light_drizzle: "weather-showers-symbolic",
- freezing_drizzle: "weather-showers-symbolic",
- heavy_freezing_drizzle: "weather-showers-symbolic",
- patchy_light_rain: "weather-showers-scattered-symbolic",
- light_rain: "weather-showers-symbolic",
- moderate_rain_at_times: "weather-showers-symbolic",
- moderate_rain: "weather-showers-symbolic",
- heavy_rain_at_times: "weather-showers-symbolic",
- heavy_rain: "weather-showers-symbolic",
- light_freezing_rain: "weather-showers-symbolic",
- moderate_or_heavy_freezing_rain: "weather-showers-symbolic",
- light_sleet: "weather-snow-symbolic",
- moderate_or_heavy_sleet: "weather-snow-symbolic",
- patchy_light_snow: "weather-snow-symbolic",
- light_snow: "weather-snow-symbolic",
- patchy_moderate_snow: "weather-snow-symbolic",
- moderate_snow: "weather-snow-symbolic",
- patchy_heavy_snow: "weather-snow-symbolic",
- heavy_snow: "weather-snow-symbolic",
- ice_pellets: "weather-showers-symbolic",
- light_rain_shower: "weather-showers-symbolic",
- moderate_or_heavy_rain_shower: "weather-showers-symbolic",
- torrential_rain_shower: "weather-showers-symbolic",
- light_sleet_showers: "weather-showers-symbolic",
- moderate_or_heavy_sleet_showers: "weather-showers-symbolic",
- light_snow_showers: "weather-snow-symbolic",
- moderate_or_heavy_snow_showers: "weather-snow-symbolic",
- light_showers_of_ice_pellets: "weather-showers-symbolic",
- moderate_or_heavy_showers_of_ice_pellets: "weather-showers-symbolic",
- patchy_light_rain_with_thunder: "weather-showers-scattered-symbolic",
- moderate_or_heavy_rain_with_thunder: "weather-showers-symbolic",
- patchy_light_snow_with_thunder: "weather-snow-symbolic",
- moderate_or_heavy_snow_with_thunder: "weather-snow-symbolic",
+ warning: 'dialog-warning-symbolic',
+ sunny: 'weather-clear-symbolic',
+ clear: 'weather-clear-night-symbolic',
+ partly_cloudy: 'weather-few-clouds-symbolic',
+ partly_cloudy_night: 'weather-few-clouds-night-symbolic',
+ cloudy: 'weather-overcast-symbolic',
+ overcast: 'weather-overcast-symbolic',
+ mist: 'weather-overcast-symbolic',
+ patchy_rain_nearby: 'weather-showers-scattered-symbolic',
+ patchy_rain_possible: 'weather-showers-scattered-symbolic',
+ patchy_snow_possible: 'weather-snow-symbolic',
+ patchy_sleet_possible: 'weather-snow-symbolic',
+ patchy_freezing_drizzle_possible: 'weather-showers-scattered-symbolic',
+ thundery_outbreaks_possible: 'weather-overcast-symbolic',
+ blowing_snow: 'weather-snow-symbolic',
+ blizzard: 'weather-snow-symbolic',
+ fog: 'weather-fog-symbolic',
+ freezing_fog: 'weather-fog-symbolic',
+ patchy_light_drizzle: 'weather-showers-scattered-symbolic',
+ light_drizzle: 'weather-showers-symbolic',
+ freezing_drizzle: 'weather-showers-symbolic',
+ heavy_freezing_drizzle: 'weather-showers-symbolic',
+ patchy_light_rain: 'weather-showers-scattered-symbolic',
+ light_rain: 'weather-showers-symbolic',
+ moderate_rain_at_times: 'weather-showers-symbolic',
+ moderate_rain: 'weather-showers-symbolic',
+ heavy_rain_at_times: 'weather-showers-symbolic',
+ heavy_rain: 'weather-showers-symbolic',
+ light_freezing_rain: 'weather-showers-symbolic',
+ moderate_or_heavy_freezing_rain: 'weather-showers-symbolic',
+ light_sleet: 'weather-snow-symbolic',
+ moderate_or_heavy_sleet: 'weather-snow-symbolic',
+ patchy_light_snow: 'weather-snow-symbolic',
+ light_snow: 'weather-snow-symbolic',
+ patchy_moderate_snow: 'weather-snow-symbolic',
+ moderate_snow: 'weather-snow-symbolic',
+ patchy_heavy_snow: 'weather-snow-symbolic',
+ heavy_snow: 'weather-snow-symbolic',
+ ice_pellets: 'weather-showers-symbolic',
+ light_rain_shower: 'weather-showers-symbolic',
+ moderate_or_heavy_rain_shower: 'weather-showers-symbolic',
+ torrential_rain_shower: 'weather-showers-symbolic',
+ light_sleet_showers: 'weather-showers-symbolic',
+ moderate_or_heavy_sleet_showers: 'weather-showers-symbolic',
+ light_snow_showers: 'weather-snow-symbolic',
+ moderate_or_heavy_snow_showers: 'weather-snow-symbolic',
+ light_showers_of_ice_pellets: 'weather-showers-symbolic',
+ moderate_or_heavy_showers_of_ice_pellets: 'weather-showers-symbolic',
+ patchy_light_rain_with_thunder: 'weather-showers-scattered-symbolic',
+ moderate_or_heavy_rain_with_thunder: 'weather-showers-symbolic',
+ patchy_light_snow_with_thunder: 'weather-snow-symbolic',
+ moderate_or_heavy_snow_with_thunder: 'weather-snow-symbolic',
},
-};
+} as const;
diff --git a/modules/icons/weather.ts b/modules/icons/weather.ts
new file mode 100644
index 0000000..90980a0
--- /dev/null
+++ b/modules/icons/weather.ts
@@ -0,0 +1,54 @@
+export const weatherIcons = {
+ warning: '',
+ sunny: '',
+ clear: '',
+ partly_cloudy: '',
+ partly_cloudy_night: '',
+ cloudy: '',
+ overcast: '',
+ mist: '',
+ patchy_rain_nearby: '',
+ patchy_rain_possible: '',
+ patchy_snow_possible: '',
+ patchy_sleet_possible: '',
+ patchy_freezing_drizzle_possible: '',
+ thundery_outbreaks_possible: '',
+ blowing_snow: '',
+ blizzard: '',
+ fog: '',
+ freezing_fog: '',
+ patchy_light_drizzle: '',
+ light_drizzle: '',
+ freezing_drizzle: '',
+ heavy_freezing_drizzle: '',
+ patchy_light_rain: '',
+ light_rain: '',
+ moderate_rain_at_times: '',
+ moderate_rain: '',
+ heavy_rain_at_times: '',
+ heavy_rain: '',
+ light_freezing_rain: '',
+ moderate_or_heavy_freezing_rain: '',
+ light_sleet: '',
+ moderate_or_heavy_sleet: '',
+ patchy_light_snow: '',
+ light_snow: '',
+ patchy_moderate_snow: '',
+ moderate_snow: '',
+ patchy_heavy_snow: '',
+ heavy_snow: '',
+ ice_pellets: '',
+ light_rain_shower: '',
+ moderate_or_heavy_rain_shower: '',
+ torrential_rain_shower: '',
+ light_sleet_showers: '',
+ moderate_or_heavy_sleet_showers: '',
+ light_snow_showers: '',
+ moderate_or_heavy_snow_showers: '',
+ light_showers_of_ice_pellets: '',
+ moderate_or_heavy_showers_of_ice_pellets: '',
+ patchy_light_rain_with_thunder: '',
+ moderate_or_heavy_rain_with_thunder: '',
+ patchy_light_snow_with_thunder: '',
+ moderate_or_heavy_snow_with_thunder: '',
+} as const;
diff --git a/modules/menus/DropdownMenu.ts b/modules/menus/DropdownMenu.ts
deleted file mode 100644
index 2c9cc18..0000000
--- a/modules/menus/DropdownMenu.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-const hyprland = await Service.import("hyprland");
-import { Exclusivity } from "lib/types/widget";
-import { bash } from "lib/utils";
-import { Monitor } from "types/service/hyprland";
-
-export const Padding = (name: string) =>
- Widget.EventBox({
- hexpand: true,
- vexpand: true,
- can_focus: true,
- child: Widget.Box(),
- setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)),
- });
-
-const moveBoxToCursor = (self: any, fixed: boolean) => {
- if (fixed) {
- return;
- }
-
- globalMousePos.connect("changed", async ({ value }) => {
- const curHyprlandMonitor = hyprland.monitors.find(m => m.id === hyprland.active.monitor.id);
- const dropdownWidth = self.child.get_allocation().width;
-
- let hyprScaling = 1;
- try {
- const monitorInfo = await bash('hyprctl monitors -j');
- const parsedMonitorInfo = JSON.parse(monitorInfo);
-
- const foundMonitor = parsedMonitorInfo.find((monitor: Monitor) =>
- monitor.id === hyprland.active.monitor.id
- );
- hyprScaling = foundMonitor?.scale || 1;
- } catch (error) {
- console.error(`Error parsing hyprland monitors: ${error}`);
- }
-
- let monWidth = curHyprlandMonitor?.width;
- let monHeight = curHyprlandMonitor?.height;
-
- if (monWidth === undefined || monHeight === undefined || hyprScaling === undefined) {
- return;
- }
-
- // If GDK Scaling is applied, then get divide width by scaling
- // to get the proper coordinates.
- // Ex: On a 2860px wide monitor... if scaling is set to 2, then the right
- // end of the monitor is the 1430th pixel.
- const gdkScale = Utils.exec('bash -c "echo $GDK_SCALE"');
-
- if (/^\d+(.\d+)?$/.test(gdkScale)) {
- const scale = parseFloat(gdkScale);
- monWidth = monWidth / scale;
- monHeight = monHeight / scale;
- } else {
- monWidth = monWidth / hyprScaling;
- monHeight = monHeight / hyprScaling;
- }
-
- // If monitor is vertical (transform = 1 || 3) swap height and width
- const isVertical = curHyprlandMonitor?.transform !== undefined
- ? curHyprlandMonitor.transform % 2 !== 0
- : false;
-
- if (isVertical) {
- [monWidth, monHeight] = [monHeight, monWidth];
- }
-
- let marginRight = monWidth - dropdownWidth / 2;
- marginRight = fixed ? marginRight - monWidth / 2 : marginRight - value[0];
- let marginLeft = monWidth - dropdownWidth - marginRight;
-
- const minimumMargin = 0;
-
- if (marginRight < minimumMargin) {
- marginRight = minimumMargin;
- marginLeft = monWidth - dropdownWidth - minimumMargin;
- }
-
- if (marginLeft < minimumMargin) {
- marginLeft = minimumMargin;
- marginRight = monWidth - dropdownWidth - minimumMargin;
- }
-
- const marginTop = 45;
- const marginBottom = monHeight - marginTop;
- self.set_margin_left(marginLeft);
- self.set_margin_right(marginRight);
- self.set_margin_bottom(marginBottom);
- });
-};
-
-// NOTE: We make the window visible for 2 seconds (on startup) so the child
-// elements can allocat their proper dimensions.
-// Otherwise the width that we rely on for menu positioning is set improperly
-// for the first time we open a menu of each type.
-const initRender = Variable(true);
-
-setTimeout(() => {
- initRender.value = false;
-}, 2000);
-
-export default ({
- name,
- child,
- layout = "center",
- transition,
- exclusivity = "ignore" as Exclusivity,
- fixed = false,
- ...props
-}) =>
- Widget.Window({
- name,
- class_names: [name, "dropdown-menu"],
- setup: (w) => w.keybind("Escape", () => App.closeWindow(name)),
- visible: initRender.bind("value"),
- keymode: "on-demand",
- exclusivity,
- layer: "top",
- anchor: ["top", "left"],
- child: Widget.EventBox({
- class_name: "parent-event",
- on_primary_click: () => App.closeWindow(name),
- on_secondary_click: () => App.closeWindow(name),
- child: Widget.Box({
- class_name: "top-eb",
- vertical: true,
- children: [
- Widget.EventBox({
- class_name: "mid-eb event-top-padding-static",
- hexpand: true,
- vexpand: false,
- can_focus: false,
- child: Widget.Box(),
- setup: (w) => {
- w.on("button-press-event", () => App.toggleWindow(name));
- w.set_margin_top(1);
- },
- }),
- Widget.EventBox({
- class_name: "mid-eb event-top-padding",
- hexpand: true,
- vexpand: false,
- can_focus: false,
- child: Widget.Box(),
- setup: (w) => {
- w.on("button-press-event", () => App.toggleWindow(name));
- w.set_margin_top(1);
- },
- }),
- Widget.EventBox({
- class_name: "in-eb menu-event-box",
- on_primary_click: () => {
- return true;
- },
- on_secondary_click: () => {
- return true;
- },
- setup: (self) => {
- moveBoxToCursor(self, fixed);
- },
- child: Widget.Box({
- class_name: "dropdown-menu-container",
- css: "padding: 1px; margin: -1px;",
- child: Widget.Revealer({
- revealChild: false,
- setup: (self) =>
- self.hook(App, (_, wname, visible) => {
- if (wname === name) self.reveal_child = visible;
- }),
- transition: "crossfade",
- transitionDuration: 350,
- child: Widget.Box({
- class_name: "dropdown-menu-container",
- can_focus: true,
- children: [child],
- }),
- }),
- }),
- }),
- ],
- }),
- }),
- ...props,
- });
diff --git a/modules/menus/audio/active/SelectedInput.ts b/modules/menus/audio/active/SelectedInput.ts
index 6bae8ae..2099ae7 100644
--- a/modules/menus/audio/active/SelectedInput.ts
+++ b/modules/menus/audio/active/SelectedInput.ts
@@ -1,31 +1,36 @@
-const audio = await Service.import("audio");
+const audio = await Service.import('audio');
+import { BarBoxChild } from 'lib/types/bar.js';
import { getIcon } from '../utils.js';
-const renderActiveInput = () => {
+const renderActiveInput = (): BarBoxChild => {
return [
Widget.Box({
- class_name: "menu-slider-container input",
+ class_name: 'menu-slider-container input',
children: [
Widget.Button({
vexpand: false,
- vpack: "end",
+ vpack: 'end',
setup: (self) => {
self.hook(audio, () => {
const mic = audio.microphone;
- const className = `menu-active-button input ${mic.is_muted ? "muted" : ""}`;
+ const className = `menu-active-button input ${mic.is_muted ? 'muted' : ''}`;
return (self.class_name = className);
});
},
- on_primary_click: () =>
- (audio.microphone.is_muted = !audio.microphone.is_muted),
+ on_primary_click: () => (audio.microphone.is_muted = !audio.microphone.is_muted),
child: Widget.Icon({
- class_name: "menu-active-icon input",
+ class_name: 'menu-active-icon input',
setup: (self) => {
self.hook(audio, () => {
- self.icon = getIcon(
- audio.microphone.volume,
- audio.microphone.is_muted,
- )["mic"];
+ const isMicMuted =
+ audio.microphone.is_muted !== null ? audio.microphone.is_muted : true;
+
+ if (audio.microphone.volume > 0) {
+ self.icon = getIcon(audio.microphone.volume, isMicMuted)['mic'];
+ return;
+ }
+
+ self.icon = getIcon(100, false)['mic'];
});
},
}),
@@ -34,15 +39,17 @@ const renderActiveInput = () => {
vertical: true,
children: [
Widget.Label({
- class_name: "menu-active input",
- hpack: "start",
- truncate: "end",
+ class_name: 'menu-active input',
+ hpack: 'start',
+ truncate: 'end',
wrap: true,
- label: audio.bind("microphone").as((v) => v.description === null ? "No input device found..." : v.description),
+ label: audio
+ .bind('microphone')
+ .as((v) => (v.description === null ? 'No input device found...' : v.description)),
}),
Widget.Slider({
- value: audio.microphone.bind("volume").as((v) => v),
- class_name: "menu-active-slider menu-slider inputs",
+ value: audio.microphone.bind('volume').as((v) => v),
+ class_name: 'menu-active-slider menu-slider inputs',
draw_value: false,
hexpand: true,
min: 0,
@@ -52,11 +59,9 @@ const renderActiveInput = () => {
],
}),
Widget.Label({
- class_name: "menu-active-percentage input",
- vpack: "end",
- label: audio.microphone
- .bind("volume")
- .as((v) => `${Math.round(v * 100)}%`),
+ class_name: 'menu-active-percentage input',
+ vpack: 'end',
+ label: audio.microphone.bind('volume').as((v) => `${Math.round(v * 100)}%`),
}),
],
}),
diff --git a/modules/menus/audio/active/SelectedPlayback.ts b/modules/menus/audio/active/SelectedPlayback.ts
index 02e5a10..2ab5887 100644
--- a/modules/menus/audio/active/SelectedPlayback.ts
+++ b/modules/menus/audio/active/SelectedPlayback.ts
@@ -1,31 +1,29 @@
-const audio = await Service.import("audio");
-import { getIcon } from "../utils.js";
+const audio = await Service.import('audio');
+import { BarBoxChild } from 'lib/types/bar.js';
+import { getIcon } from '../utils.js';
-const renderActivePlayback = () => {
+const renderActivePlayback = (): BarBoxChild => {
return [
Widget.Box({
- class_name: "menu-slider-container playback",
+ class_name: 'menu-slider-container playback',
children: [
Widget.Button({
vexpand: false,
- vpack: "end",
+ vpack: 'end',
setup: (self) => {
self.hook(audio, () => {
const spkr = audio.speaker;
- const className = `menu-active-button playback ${spkr.is_muted ? "muted" : ""}`;
+ const className = `menu-active-button playback ${spkr.is_muted ? 'muted' : ''}`;
return (self.class_name = className);
});
},
- on_primary_click: () =>
- (audio.speaker.is_muted = !audio.speaker.is_muted),
+ on_primary_click: () => (audio.speaker.is_muted = !audio.speaker.is_muted),
child: Widget.Icon({
- class_name: "menu-active-icon playback",
+ class_name: 'menu-active-icon playback',
setup: (self) => {
self.hook(audio, () => {
- self.icon = getIcon(
- audio.speaker.volume,
- audio.speaker.is_muted,
- )["spkr"];
+ const isSpeakerMuted = audio.speaker.is_muted !== null ? audio.speaker.is_muted : true;
+ self.icon = getIcon(audio.speaker.volume, isSpeakerMuted)['spkr'];
});
},
}),
@@ -34,16 +32,16 @@ const renderActivePlayback = () => {
vertical: true,
children: [
Widget.Label({
- class_name: "menu-active playback",
- hpack: "start",
- truncate: "end",
+ class_name: 'menu-active playback',
+ hpack: 'start',
+ truncate: 'end',
expand: true,
wrap: true,
- label: audio.bind("speaker").as((v) => v.description || ""),
+ label: audio.bind('speaker').as((v) => v.description || ''),
}),
Widget.Slider({
- value: audio["speaker"].bind("volume"),
- class_name: "menu-active-slider menu-slider playback",
+ value: audio['speaker'].bind('volume'),
+ class_name: 'menu-active-slider menu-slider playback',
draw_value: false,
hexpand: true,
min: 0,
@@ -53,11 +51,9 @@ const renderActivePlayback = () => {
],
}),
Widget.Label({
- vpack: "end",
- class_name: "menu-active-percentage playback",
- label: audio.speaker
- .bind("volume")
- .as((v) => `${Math.round(v * 100)}%`),
+ vpack: 'end',
+ class_name: 'menu-active-percentage playback',
+ label: audio.speaker.bind('volume').as((v) => `${Math.round(v * 100)}%`),
}),
],
}),
diff --git a/modules/menus/audio/active/index.ts b/modules/menus/audio/active/index.ts
index 84d14bf..fc1c65a 100644
--- a/modules/menus/audio/active/index.ts
+++ b/modules/menus/audio/active/index.ts
@@ -1,39 +1,40 @@
-import { renderActiveInput } from "./SelectedInput.js";
-import { renderActivePlayback } from "./SelectedPlayback.js";
+import { BarBoxChild } from 'lib/types/bar.js';
+import { renderActiveInput } from './SelectedInput.js';
+import { renderActivePlayback } from './SelectedPlayback.js';
-const activeDevices = () => {
- return Widget.Box({
- class_name: "menu-section-container volume",
- vertical: true,
- children: [
- Widget.Box({
- class_name: "menu-label-container volume selected",
- hpack: "fill",
- child: Widget.Label({
- class_name: "menu-label audio volume",
- hexpand: true,
- hpack: "start",
- label: "Volume",
- }),
- }),
- Widget.Box({
- class_name: "menu-items-section selected",
+const activeDevices = (): BarBoxChild => {
+ return Widget.Box({
+ class_name: 'menu-section-container volume',
vertical: true,
children: [
- Widget.Box({
- class_name: "menu-active-container playback",
- vertical: true,
- children: renderActivePlayback(),
- }),
- Widget.Box({
- class_name: "menu-active-container input",
- vertical: true,
- children: renderActiveInput(),
- }),
+ Widget.Box({
+ class_name: 'menu-label-container volume selected',
+ hpack: 'fill',
+ child: Widget.Label({
+ class_name: 'menu-label audio volume',
+ hexpand: true,
+ hpack: 'start',
+ label: 'Volume',
+ }),
+ }),
+ Widget.Box({
+ class_name: 'menu-items-section selected',
+ vertical: true,
+ children: [
+ Widget.Box({
+ class_name: 'menu-active-container playback',
+ vertical: true,
+ children: renderActivePlayback(),
+ }),
+ Widget.Box({
+ class_name: 'menu-active-container input',
+ vertical: true,
+ children: renderActiveInput(),
+ }),
+ ],
+ }),
],
- }),
- ],
- });
+ });
};
export { activeDevices };
diff --git a/modules/menus/audio/available/InputDevices.ts b/modules/menus/audio/available/InputDevices.ts
index 42b2a76..8c75a5a 100644
--- a/modules/menus/audio/available/InputDevices.ts
+++ b/modules/menus/audio/available/InputDevices.ts
@@ -1,7 +1,8 @@
-const audio = await Service.import("audio");
-import { Stream } from "types/service/audio";
+const audio = await Service.import('audio');
+import { InputDevices } from 'lib/types/audio';
+import { Stream } from 'types/service/audio';
-const renderInputDevices = (inputDevices: Stream[]) => {
+const renderInputDevices = (inputDevices: Stream[]): InputDevices => {
if (inputDevices.length === 0) {
return [
Widget.Button({
@@ -9,11 +10,11 @@ const renderInputDevices = (inputDevices: Stream[]) => {
child: Widget.Box({
children: [
Widget.Box({
- hpack: "start",
+ hpack: 'start',
children: [
Widget.Label({
- class_name: "menu-button-name input",
- label: "No input devices found...",
+ class_name: 'menu-button-name input',
+ label: 'No input devices found...',
}),
],
}),
@@ -29,28 +30,28 @@ const renderInputDevices = (inputDevices: Stream[]) => {
child: Widget.Box({
children: [
Widget.Box({
- hpack: "start",
+ hpack: 'start',
children: [
Widget.Label({
wrap: true,
class_name: audio.microphone
- .bind("description")
+ .bind('description')
.as((v) =>
device.description === v
- ? "menu-button-icon active input txt-icon"
- : "menu-button-icon input txt-icon",
+ ? 'menu-button-icon active input txt-icon'
+ : 'menu-button-icon input txt-icon',
),
- label: "",
+ label: '',
}),
Widget.Label({
- truncate: "end",
+ truncate: 'end',
wrap: true,
class_name: audio.microphone
- .bind("description")
+ .bind('description')
.as((v) =>
device.description === v
- ? "menu-button-name active input"
- : "menu-button-name input",
+ ? 'menu-button-name active input'
+ : 'menu-button-name input',
),
label: device.description,
}),
diff --git a/modules/menus/audio/available/PlaybackDevices.ts b/modules/menus/audio/available/PlaybackDevices.ts
index 67bdd54..02bc618 100644
--- a/modules/menus/audio/available/PlaybackDevices.ts
+++ b/modules/menus/audio/available/PlaybackDevices.ts
@@ -1,16 +1,17 @@
-const audio = await Service.import("audio");
-import { Stream } from "types/service/audio";
+const audio = await Service.import('audio');
+import { PlaybackDevices } from 'lib/types/audio';
+import { Stream } from 'types/service/audio';
-const renderPlaybacks = (playbackDevices: Stream[]) => {
+const renderPlaybacks = (playbackDevices: Stream[]): PlaybackDevices => {
return playbackDevices.map((device) => {
- if (device.description === "Dummy Output") {
+ if (device.description === 'Dummy Output') {
return Widget.Box({
- class_name: "menu-unfound-button playback",
+ class_name: 'menu-unfound-button playback',
child: Widget.Box({
children: [
Widget.Label({
- class_name: "menu-button-name playback",
- label: "No playback devices found...",
+ class_name: 'menu-button-name playback',
+ label: 'No playback devices found...',
}),
],
}),
@@ -22,29 +23,29 @@ const renderPlaybacks = (playbackDevices: Stream[]) => {
child: Widget.Box({
children: [
Widget.Box({
- hpack: "start",
+ hpack: 'start',
children: [
Widget.Label({
- truncate: "end",
+ truncate: 'end',
wrap: true,
class_name: audio.speaker
- .bind("description")
+ .bind('description')
.as((v) =>
device.description === v
- ? "menu-button-icon active playback txt-icon"
- : "menu-button-icon playback txt-icon",
+ ? 'menu-button-icon active playback txt-icon'
+ : 'menu-button-icon playback txt-icon',
),
- label: "",
+ label: '',
}),
Widget.Label({
- truncate: "end",
+ truncate: 'end',
wrap: true,
class_name: audio.speaker
- .bind("description")
+ .bind('description')
.as((v) =>
device.description === v
- ? "menu-button-name active playback"
- : "menu-button-name playback",
+ ? 'menu-button-name active playback'
+ : 'menu-button-name playback',
),
label: device.description,
}),
diff --git a/modules/menus/audio/available/index.ts b/modules/menus/audio/available/index.ts
index 1dca28d..e9b0d48 100644
--- a/modules/menus/audio/available/index.ts
+++ b/modules/menus/audio/available/index.ts
@@ -1,66 +1,63 @@
-const audio = await Service.import("audio");
-import { renderInputDevices } from "./InputDevices.js";
-import { renderPlaybacks } from "./PlaybackDevices.js";
+const audio = await Service.import('audio');
+import { BoxWidget } from 'lib/types/widget.js';
+import { renderInputDevices } from './InputDevices.js';
+import { renderPlaybacks } from './PlaybackDevices.js';
-const availableDevices = () => {
+const availableDevices = (): BoxWidget => {
return Widget.Box({
vertical: true,
children: [
Widget.Box({
- class_name: "menu-section-container playback",
+ class_name: 'menu-section-container playback',
vertical: true,
children: [
Widget.Box({
- class_name: "menu-label-container playback",
- hpack: "fill",
+ class_name: 'menu-label-container playback',
+ hpack: 'fill',
child: Widget.Label({
- class_name: "menu-label audio playback",
+ class_name: 'menu-label audio playback',
hexpand: true,
- hpack: "start",
- label: "Playback Devices",
+ hpack: 'start',
+ label: 'Playback Devices',
}),
}),
Widget.Box({
- class_name: "menu-items-section playback",
+ class_name: 'menu-items-section playback',
vertical: true,
children: [
Widget.Box({
- class_name: "menu-container playback",
+ class_name: 'menu-container playback',
vertical: true,
children: [
Widget.Box({
vertical: true,
- children: audio
- .bind("speakers")
- .as((v) => renderPlaybacks(v)),
+ children: audio.bind('speakers').as((v) => renderPlaybacks(v)),
}),
],
}),
],
}),
Widget.Box({
- class_name: "menu-label-container input",
- hpack: "fill",
+ class_name: 'menu-label-container input',
+ hpack: 'fill',
child: Widget.Label({
- class_name: "menu-label audio input",
+ class_name: 'menu-label audio input',
hexpand: true,
- hpack: "start",
- label: "Input Devices",
+ hpack: 'start',
+ label: 'Input Devices',
}),
}),
Widget.Box({
- class_name: "menu-items-section input",
+ class_name: 'menu-items-section input',
vertical: true,
children: [
Widget.Box({
- class_name: "menu-container input",
+ class_name: 'menu-container input',
vertical: true,
children: [
Widget.Box({
vertical: true,
- children: audio
- .bind("microphones")
- .as((v) => renderInputDevices(v)),
+ children: audio.bind('microphones').as((v) => renderInputDevices(v)),
}),
],
}),
diff --git a/modules/menus/audio/index.ts b/modules/menus/audio/index.ts
index f39231b..5bf317d 100644
--- a/modules/menus/audio/index.ts
+++ b/modules/menus/audio/index.ts
@@ -1,24 +1,23 @@
-import DropdownMenu from "../DropdownMenu.js";
-import { activeDevices } from "./active/index.js";
-import { availableDevices } from "./available/index.js";
+import Window from 'types/widgets/window.js';
+import DropdownMenu from '../shared/dropdown/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 => {
return DropdownMenu({
- name: "audiomenu",
- transition: "crossfade",
+ name: 'audiomenu',
+ transition: 'crossfade',
child: Widget.Box({
- class_name: "menu-items audio",
- hpack: "fill",
+ class_name: 'menu-items audio',
+ hpack: 'fill',
hexpand: true,
child: Widget.Box({
vertical: true,
- hpack: "fill",
+ hpack: 'fill',
hexpand: true,
- class_name: "menu-items-container audio",
- children: [
- activeDevices(),
- availableDevices(),
- ],
+ class_name: 'menu-items-container audio',
+ children: [activeDevices(), availableDevices()],
}),
}),
});
diff --git a/modules/menus/audio/utils.ts b/modules/menus/audio/utils.ts
index 2aa71a7..aa1de5c 100644
--- a/modules/menus/audio/utils.ts
+++ b/modules/menus/audio/utils.ts
@@ -1,27 +1,29 @@
-const getIcon = (audioVol, isMuted) => {
- const speakerIcons = {
- 101: "audio-volume-overamplified-symbolic",
- 66: "audio-volume-high-symbolic",
- 34: "audio-volume-medium-symbolic",
- 1: "audio-volume-low-symbolic",
- 0: "audio-volume-muted-symbolic",
- };
+const speakerIcons = {
+ 101: 'audio-volume-overamplified-symbolic',
+ 66: 'audio-volume-high-symbolic',
+ 34: 'audio-volume-medium-symbolic',
+ 1: 'audio-volume-low-symbolic',
+ 0: 'audio-volume-muted-symbolic',
+} as const;
- const inputIcons = {
- 66: "microphone-sensitivity-high-symbolic",
- 34: "microphone-sensitivity-medium-symbolic",
- 1: "microphone-sensitivity-low-symbolic",
- 0: "microphone-disabled-symbolic",
- };
+const inputIcons = {
+ 101: 'microphone-sensitivity-high-symbolic',
+ 66: 'microphone-sensitivity-high-symbolic',
+ 34: 'microphone-sensitivity-medium-symbolic',
+ 1: 'microphone-sensitivity-low-symbolic',
+ 0: 'microphone-disabled-symbolic',
+};
- const icon = isMuted
- ? 0
- : [101, 66, 34, 1, 0].find((threshold) => threshold <= audioVol * 100);
+type IconVolumes = keyof typeof speakerIcons;
- return {
- spkr: speakerIcons[icon],
- mic: inputIcons[icon],
- };
+const getIcon = (audioVol: number, isMuted: boolean): Record => {
+ const thresholds: IconVolumes[] = [101, 66, 34, 1, 0];
+ const icon = isMuted ? 0 : thresholds.find((threshold) => threshold <= audioVol * 100) || 0;
+
+ return {
+ spkr: speakerIcons[icon],
+ mic: inputIcons[icon],
+ };
};
export { getIcon };
diff --git a/modules/menus/bluetooth/devices/connectedControls.ts b/modules/menus/bluetooth/devices/connectedControls.ts
index 0c7e6c2..62e8345 100644
--- a/modules/menus/bluetooth/devices/connectedControls.ts
+++ b/modules/menus/bluetooth/devices/connectedControls.ts
@@ -1,74 +1,67 @@
-import { BluetoothDevice } from "types/service/bluetooth";
+import { BoxWidget } from 'lib/types/widget';
+import { BluetoothDevice } from 'types/service/bluetooth';
-const connectedControls = (dev: BluetoothDevice, connectedDevices: BluetoothDevice[]) => {
+const connectedControls = (dev: BluetoothDevice, connectedDevices: BluetoothDevice[]): BoxWidget => {
if (!connectedDevices.includes(dev.address)) {
return Widget.Box({});
}
return Widget.Box({
- vpack: "start",
- class_name: "bluetooth-controls",
+ vpack: 'start',
+ class_name: 'bluetooth-controls',
children: [
Widget.Button({
- class_name: "menu-icon-button unpair bluetooth",
+ class_name: 'menu-icon-button unpair bluetooth',
child: Widget.Label({
- tooltip_text: dev.paired ? "Unpair" : "Pair",
- class_name: "menu-icon-button-label unpair bluetooth txt-icon",
- label: dev.paired ? "" : "",
+ tooltip_text: dev.paired ? 'Unpair' : 'Pair',
+ class_name: 'menu-icon-button-label unpair bluetooth txt-icon',
+ label: dev.paired ? '' : '',
}),
on_primary_click: () =>
Utils.execAsync([
- "bash",
- "-c",
- `bluetoothctl ${dev.paired ? "unpair" : "pair"} ${dev.address}`,
+ 'bash',
+ '-c',
+ `bluetoothctl ${dev.paired ? 'unpair' : 'pair'} ${dev.address}`,
]).catch((err) =>
- console.error(
- `bluetoothctl ${dev.paired ? "unpair" : "pair"} ${dev.address}`,
- err,
- ),
+ console.error(`bluetoothctl ${dev.paired ? 'unpair' : 'pair'} ${dev.address}`, err),
),
}),
Widget.Button({
- class_name: "menu-icon-button disconnect bluetooth",
+ class_name: 'menu-icon-button disconnect bluetooth',
child: Widget.Label({
- tooltip_text: dev.connected ? "Disconnect" : "Connect",
- class_name: "menu-icon-button-label disconnect bluetooth txt-icon",
- label: dev.connected ? "" : "",
+ tooltip_text: dev.connected ? 'Disconnect' : 'Connect',
+ class_name: 'menu-icon-button-label disconnect bluetooth txt-icon',
+ label: dev.connected ? '' : '',
}),
on_primary_click: () => dev.setConnection(!dev.connected),
}),
Widget.Button({
- class_name: "menu-icon-button untrust bluetooth",
+ class_name: 'menu-icon-button untrust bluetooth',
child: Widget.Label({
- tooltip_text: dev.trusted ? "Untrust" : "Trust",
- class_name: "menu-icon-button-label untrust bluetooth txt-icon",
- label: dev.trusted ? "" : "",
+ tooltip_text: dev.trusted ? 'Untrust' : 'Trust',
+ class_name: 'menu-icon-button-label untrust bluetooth txt-icon',
+ label: dev.trusted ? '' : '',
}),
on_primary_click: () =>
Utils.execAsync([
- "bash",
- "-c",
- `bluetoothctl ${dev.trusted ? "untrust" : "trust"} ${dev.address}`,
+ 'bash',
+ '-c',
+ `bluetoothctl ${dev.trusted ? 'untrust' : 'trust'} ${dev.address}`,
]).catch((err) =>
- console.error(
- `bluetoothctl ${dev.trusted ? "untrust" : "trust"} ${dev.address}`,
- err,
- ),
+ console.error(`bluetoothctl ${dev.trusted ? 'untrust' : 'trust'} ${dev.address}`, err),
),
}),
Widget.Button({
- class_name: "menu-icon-button delete bluetooth",
+ class_name: 'menu-icon-button delete bluetooth',
child: Widget.Label({
- tooltip_text: "Forget",
- class_name: "menu-icon-button-label delete bluetooth txt-icon",
- label: "",
+ tooltip_text: 'Forget',
+ class_name: 'menu-icon-button-label delete bluetooth txt-icon',
+ label: '',
}),
on_primary_click: () => {
- Utils.execAsync([
- "bash",
- "-c",
- `bluetoothctl remove ${dev.address}`,
- ]).catch((err) => console.error("Bluetooth Remove", err));
+ Utils.execAsync(['bash', '-c', `bluetoothctl remove ${dev.address}`]).catch((err) =>
+ console.error('Bluetooth Remove', err),
+ );
},
}),
],
diff --git a/modules/menus/bluetooth/devices/devicelist.ts b/modules/menus/bluetooth/devices/devicelist.ts
index 6827145..e1fdcc9 100644
--- a/modules/menus/bluetooth/devices/devicelist.ts
+++ b/modules/menus/bluetooth/devices/devicelist.ts
@@ -1,32 +1,31 @@
-import { Bluetooth } from "types/service/bluetooth.js";
-import Box from "types/widgets/box.js";
-import { connectedControls } from "./connectedControls.js";
-import { getBluetoothIcon } from "../utils.js";
-import Gtk from "types/@girs/gtk-3.0/gtk-3.0.js";
+import { Bluetooth } from 'types/service/bluetooth.js';
+import Box from 'types/widgets/box.js';
+import { connectedControls } from './connectedControls.js';
+import { getBluetoothIcon } from '../utils.js';
+import Gtk from 'types/@girs/gtk-3.0/gtk-3.0.js';
+import { Attribute, Child } from 'lib/types/widget.js';
-const devices = (bluetooth: Bluetooth, self: Box) => {
+const devices = (bluetooth: Bluetooth, self: Box): Box => {
return self.hook(bluetooth, () => {
if (!bluetooth.enabled) {
return (self.child = Widget.Box({
- class_name: "bluetooth-items",
+ class_name: 'bluetooth-items',
vertical: true,
expand: true,
- vpack: "center",
- hpack: "center",
+ vpack: 'center',
+ hpack: 'center',
children: [
Widget.Label({
- class_name: "bluetooth-disabled dim",
+ class_name: 'bluetooth-disabled dim',
hexpand: true,
- label: "Bluetooth is disabled",
+ label: 'Bluetooth is disabled',
}),
],
}));
}
const availableDevices = bluetooth.devices
- .filter(
- (btDev) => btDev.name !== null,
- )
+ .filter((btDev) => btDev.name !== null)
.sort((a, b) => {
if (a.connected || a.paired) {
return -1;
@@ -39,25 +38,23 @@ const devices = (bluetooth: Bluetooth, self: Box) => {
return b.name - a.name;
});
- const conDevNames = availableDevices
- .filter((d) => d.connected || d.paired)
- .map((d) => d.address);
+ const conDevNames = availableDevices.filter((d) => d.connected || d.paired).map((d) => d.address);
if (!availableDevices.length) {
return (self.child = Widget.Box({
- class_name: "bluetooth-items",
+ class_name: 'bluetooth-items',
vertical: true,
expand: true,
- vpack: "center",
- hpack: "center",
+ vpack: 'center',
+ hpack: 'center',
children: [
Widget.Label({
- class_name: "no-bluetooth-devices dim",
+ class_name: 'no-bluetooth-devices dim',
hexpand: true,
- label: "No devices currently found",
+ label: 'No devices currently found',
}),
Widget.Label({
- class_name: "search-bluetooth-label dim",
+ class_name: 'search-bluetooth-label dim',
hexpand: true,
label: "Press '' to search",
}),
@@ -74,41 +71,40 @@ const devices = (bluetooth: Bluetooth, self: Box) => {
hexpand: true,
class_name: `bluetooth-element-item ${device}`,
on_primary_click: () => {
- if (!conDevNames.includes(device.address))
- device.setConnection(true);
+ if (!conDevNames.includes(device.address)) device.setConnection(true);
},
child: Widget.Box({
hexpand: true,
children: [
Widget.Box({
hexpand: true,
- hpack: "start",
- class_name: "menu-button-container",
+ hpack: 'start',
+ class_name: 'menu-button-container',
children: [
Widget.Label({
- vpack: "start",
- class_name: `menu-button-icon bluetooth ${conDevNames.includes(device.address) ? "active" : ""} txt-icon`,
- label: getBluetoothIcon(`${device["icon-name"]}-symbolic`),
+ vpack: 'start',
+ class_name: `menu-button-icon bluetooth ${conDevNames.includes(device.address) ? 'active' : ''} txt-icon`,
+ label: getBluetoothIcon(`${device['icon_name']}-symbolic`),
}),
Widget.Box({
vertical: true,
- vpack: "center",
+ vpack: 'center',
children: [
Widget.Label({
- vpack: "center",
- hpack: "start",
- class_name: "menu-button-name bluetooth",
- truncate: "end",
+ vpack: 'center',
+ hpack: 'start',
+ class_name: 'menu-button-name bluetooth',
+ truncate: 'end',
wrap: true,
label: device.alias,
}),
Widget.Revealer({
- hpack: "start",
+ hpack: 'start',
reveal_child: device.connected || device.paired,
child: Widget.Label({
- hpack: "start",
- class_name: "connection-status dim",
- label: device.connected ? "Connected" : "Paired",
+ hpack: 'start',
+ class_name: 'connection-status dim',
+ label: device.connected ? 'Connected' : 'Paired',
}),
}),
],
@@ -116,14 +112,14 @@ const devices = (bluetooth: Bluetooth, self: Box) => {
],
}),
Widget.Box({
- hpack: "end",
+ hpack: 'end',
children: device.connecting
? [
- Widget.Spinner({
- vpack: "start",
- class_name: "spinner bluetooth",
- }),
- ]
+ Widget.Spinner({
+ vpack: 'start',
+ class_name: 'spinner bluetooth',
+ }),
+ ]
: [],
}),
],
diff --git a/modules/menus/bluetooth/devices/index.ts b/modules/menus/bluetooth/devices/index.ts
index 9b7d3a1..31315d5 100644
--- a/modules/menus/bluetooth/devices/index.ts
+++ b/modules/menus/bluetooth/devices/index.ts
@@ -1,17 +1,18 @@
-const bluetooth = await Service.import("bluetooth");
-import { label } from "./label.js";
-import { devices } from "./devicelist.js";
+const bluetooth = await Service.import('bluetooth');
+import { label } from './label.js';
+import { devices } from './devicelist.js';
+import { BoxWidget } from 'lib/types/widget.js';
-const Devices = () => {
+const Devices = (): BoxWidget => {
return Widget.Box({
- class_name: "menu-section-container",
+ class_name: 'menu-section-container',
vertical: true,
children: [
label(bluetooth),
Widget.Box({
- class_name: "menu-items-section",
+ class_name: 'menu-items-section',
child: Widget.Box({
- class_name: "menu-content",
+ class_name: 'menu-content',
vertical: true,
setup: (self) => {
devices(bluetooth, self);
diff --git a/modules/menus/bluetooth/devices/label.ts b/modules/menus/bluetooth/devices/label.ts
index d5b8555..45fabf6 100644
--- a/modules/menus/bluetooth/devices/label.ts
+++ b/modules/menus/bluetooth/devices/label.ts
@@ -1,7 +1,10 @@
-import { Bluetooth } from "types/service/bluetooth";
-const label = (bluetooth: Bluetooth) => {
+import { BoxWidget } from 'lib/types/widget';
+import { Bluetooth } from 'types/service/bluetooth';
+
+const label = (bluetooth: Bluetooth): BoxWidget => {
const searchInProgress = Variable(false);
- const startRotation = () => {
+
+ const startRotation = (): void => {
searchInProgress.value = true;
setTimeout(() => {
searchInProgress.value = false;
@@ -9,61 +12,48 @@ const label = (bluetooth: Bluetooth) => {
};
return Widget.Box({
- class_name: "menu-label-container",
- hpack: "fill",
- vpack: "start",
+ class_name: 'menu-label-container',
+ hpack: 'fill',
+ vpack: 'start',
children: [
Widget.Label({
- class_name: "menu-label",
- vpack: "center",
- hpack: "start",
- label: "Bluetooth",
+ class_name: 'menu-label',
+ vpack: 'center',
+ hpack: 'start',
+ label: 'Bluetooth',
}),
Widget.Box({
- class_name: "controls-container",
- vpack: "start",
+ class_name: 'controls-container',
+ vpack: 'start',
children: [
Widget.Switch({
- class_name: "menu-switch bluetooth",
+ class_name: 'menu-switch bluetooth',
hexpand: true,
- hpack: "end",
- active: bluetooth.bind("enabled"),
+ hpack: 'end',
+ active: bluetooth.bind('enabled'),
on_activate: ({ active }) => {
searchInProgress.value = false;
- Utils.execAsync([
- "bash",
- "-c",
- `bluetoothctl power ${active ? "on" : "off"}`,
- ]).catch((err) =>
- console.error(
- `bluetoothctl power ${active ? "on" : "off"}`,
- err,
- ),
+ Utils.execAsync(['bash', '-c', `bluetoothctl power ${active ? 'on' : 'off'}`]).catch(
+ (err) => console.error(`bluetoothctl power ${active ? 'on' : 'off'}`, err),
);
},
}),
Widget.Separator({
- class_name: "menu-separator bluetooth",
+ class_name: 'menu-separator bluetooth',
}),
Widget.Button({
- vpack: "center",
- class_name: "menu-icon-button search",
+ vpack: 'center',
+ class_name: 'menu-icon-button search',
on_primary_click: () => {
startRotation();
- Utils.execAsync([
- "bash",
- "-c",
- "bluetoothctl --timeout 120 scan on",
- ]).catch((err) => {
+ Utils.execAsync(['bash', '-c', 'bluetoothctl --timeout 120 scan on']).catch((err) => {
searchInProgress.value = false;
- console.error("bluetoothctl --timeout 120 scan on", err);
+ console.error('bluetoothctl --timeout 120 scan on', err);
});
},
child: Widget.Icon({
- class_name: searchInProgress
- .bind("value")
- .as((v) => (v ? "spinning" : "")),
- icon: "view-refresh-symbolic",
+ class_name: searchInProgress.bind('value').as((v) => (v ? 'spinning' : '')),
+ icon: 'view-refresh-symbolic',
}),
}),
],
diff --git a/modules/menus/bluetooth/index.ts b/modules/menus/bluetooth/index.ts
index 9557faf..3eb722e 100644
--- a/modules/menus/bluetooth/index.ts
+++ b/modules/menus/bluetooth/index.ts
@@ -1,21 +1,23 @@
-import DropdownMenu from "../DropdownMenu.js";
-import { Devices } from "./devices/index.js";
+import Window from 'types/widgets/window.js';
+import DropdownMenu from '../shared/dropdown/index.js';
+import { Devices } from './devices/index.js';
+import { Attribute, Child } from 'lib/types/widget.js';
-export default () => {
- return DropdownMenu({
- name: "bluetoothmenu",
- transition: "crossfade",
- child: Widget.Box({
- class_name: "menu-items bluetooth",
- hpack: "fill",
- hexpand: true,
- child: Widget.Box({
- vertical: true,
- hpack: "fill",
- hexpand: true,
- class_name: "menu-items-container bluetooth",
- child: Devices(),
- }),
- }),
- });
+export default (): Window => {
+ return DropdownMenu({
+ name: 'bluetoothmenu',
+ transition: 'crossfade',
+ child: Widget.Box({
+ class_name: 'menu-items bluetooth',
+ hpack: 'fill',
+ hexpand: true,
+ child: Widget.Box({
+ vertical: true,
+ hpack: 'fill',
+ hexpand: true,
+ class_name: 'menu-items-container bluetooth',
+ child: Devices(),
+ }),
+ }),
+ });
};
diff --git a/modules/menus/bluetooth/utils.ts b/modules/menus/bluetooth/utils.ts
index 2024f8b..c305538 100644
--- a/modules/menus/bluetooth/utils.ts
+++ b/modules/menus/bluetooth/utils.ts
@@ -1,31 +1,29 @@
-const getBluetoothIcon = (iconName: string) => {
+const getBluetoothIcon = (iconName: string): string => {
const deviceIconMap = [
- ["^audio-card*", ""],
- ["^audio-headphones*", ""],
- ["^audio-headset*", ""],
- ["^audio-input*", ""],
- ["^audio-speakers*", ""],
- ["^bluetooth*", ""],
- ["^camera*", ""],
- ["^computer*", ""],
- ["^input-gaming*", ""],
- ["^input-keyboard*", ""],
- ["^input-mouse*", ""],
- ["^input-tablet*", ""],
- ["^media*", ""],
- ["^modem*", ""],
- ["^network*", ""],
- ["^phone*", ""],
- ["^printer*", ""],
- ["^scanner*", ""],
- ["^video-camera*", ""],
+ ['^audio-card*', ''],
+ ['^audio-headphones*', ''],
+ ['^audio-headset*', ''],
+ ['^audio-input*', ''],
+ ['^audio-speakers*', ''],
+ ['^bluetooth*', ''],
+ ['^camera*', ''],
+ ['^computer*', ''],
+ ['^input-gaming*', ''],
+ ['^input-keyboard*', ''],
+ ['^input-mouse*', ''],
+ ['^input-tablet*', ''],
+ ['^media*', ''],
+ ['^modem*', ''],
+ ['^network*', ''],
+ ['^phone*', ''],
+ ['^printer*', ''],
+ ['^scanner*', ''],
+ ['^video-camera*', ''],
];
- const foundMatch = deviceIconMap.find((icon) =>
- RegExp(icon[0]).test(iconName.toLowerCase()),
- );
+ const foundMatch = deviceIconMap.find((icon) => RegExp(icon[0]).test(iconName.toLowerCase()));
- return foundMatch ? foundMatch[1] : "";
+ return foundMatch ? foundMatch[1] : '';
};
export { getBluetoothIcon };
diff --git a/modules/menus/calendar/calendar.ts b/modules/menus/calendar/calendar.ts
index 4d50c0c..d2af59e 100644
--- a/modules/menus/calendar/calendar.ts
+++ b/modules/menus/calendar/calendar.ts
@@ -1,22 +1,24 @@
-const CalendarWidget = () => {
- return Widget.Box({
- class_name: "calendar-menu-item-container calendar",
- hpack: "fill",
- vpack: "fill",
- expand: true,
- child: Widget.Box({
- class_name: "calendar-container-box",
- child: Widget.Calendar({
+import { BoxWidget } from 'lib/types/widget';
+
+const CalendarWidget = (): BoxWidget => {
+ return Widget.Box({
+ class_name: 'calendar-menu-item-container calendar',
+ hpack: 'fill',
+ vpack: 'fill',
expand: true,
- hpack: "fill",
- vpack: "fill",
- class_name: "calendar-menu-widget",
- showDayNames: true,
- showDetails: false,
- showHeading: true,
- }),
- }),
- });
+ child: Widget.Box({
+ class_name: 'calendar-container-box',
+ child: Widget.Calendar({
+ expand: true,
+ hpack: 'fill',
+ vpack: 'fill',
+ class_name: 'calendar-menu-widget',
+ showDayNames: true,
+ showDetails: false,
+ showHeading: true,
+ }),
+ }),
+ });
};
export { CalendarWidget };
diff --git a/modules/menus/calendar/index.ts b/modules/menus/calendar/index.ts
index d985554..4ff2525 100644
--- a/modules/menus/calendar/index.ts
+++ b/modules/menus/calendar/index.ts
@@ -1,29 +1,31 @@
-import DropdownMenu from "../DropdownMenu.js";
-import { TimeWidget } from "./time/index.js";
-import { CalendarWidget } from "./calendar.js";
-import { WeatherWidget } from "./weather/index.js";
+import DropdownMenu from '../shared/dropdown/index.js';
+import { TimeWidget } from './time/index.js';
+import { CalendarWidget } from './calendar.js';
+import { WeatherWidget } from './weather/index.js';
+import Window from 'types/widgets/window.js';
+import { Attribute, Child } from 'lib/types/widget.js';
-export default () => {
- return DropdownMenu({
- name: "calendarmenu",
- transition: "crossfade",
- child: Widget.Box({
- class_name: "calendar-menu-content",
- css: "padding: 1px; margin: -1px;",
- vexpand: false,
- children: [
- Widget.Box({
- class_name: "calendar-content-container",
- vertical: true,
- children: [
- Widget.Box({
- class_name: "calendar-content-items",
- vertical: true,
- children: [TimeWidget(), CalendarWidget(), WeatherWidget()],
- }),
- ],
+export default (): Window => {
+ return DropdownMenu({
+ name: 'calendarmenu',
+ transition: 'crossfade',
+ child: Widget.Box({
+ class_name: 'calendar-menu-content',
+ css: 'padding: 1px; margin: -1px;',
+ vexpand: false,
+ children: [
+ Widget.Box({
+ class_name: 'calendar-content-container',
+ vertical: true,
+ children: [
+ Widget.Box({
+ class_name: 'calendar-content-items',
+ vertical: true,
+ children: [TimeWidget(), CalendarWidget(), WeatherWidget()],
+ }),
+ ],
+ }),
+ ],
}),
- ],
- }),
- });
+ });
};
diff --git a/modules/menus/calendar/time/index.ts b/modules/menus/calendar/time/index.ts
index 11a4639..0812a61 100644
--- a/modules/menus/calendar/time/index.ts
+++ b/modules/menus/calendar/time/index.ts
@@ -1,69 +1,70 @@
-import options from "options";
+import { BoxWidget } from 'lib/types/widget';
+import options from 'options';
const { military } = options.menus.clock.time;
-const time = Variable("", {
- poll: [1000, 'date "+%I:%M:%S"'],
+const time = Variable('', {
+ poll: [1000, 'date "+%I:%M:%S"'],
});
-const period = Variable("", {
- poll: [1000, 'date "+%p"'],
+const period = Variable('', {
+ poll: [1000, 'date "+%p"'],
});
-const militaryTime = Variable("", {
- poll: [1000, 'date "+%H:%M:%S"'],
+const militaryTime = Variable('', {
+ poll: [1000, 'date "+%H:%M:%S"'],
});
-const TimeWidget = () => {
- return Widget.Box({
- class_name: "calendar-menu-item-container clock",
- hexpand: true,
- vpack: "center",
- hpack: "fill",
- child: Widget.Box({
- hexpand: true,
- vpack: "center",
- hpack: "center",
- class_name: "clock-content-items",
- children: military.bind("value").as((is24hr) => {
- if (!is24hr) {
- return [
- Widget.Box({
- hpack: "center",
- children: [
- Widget.Label({
- class_name: "clock-content-time",
- label: time.bind(),
- }),
- ],
+const TimeWidget = (): BoxWidget => {
+ return Widget.Box({
+ class_name: 'calendar-menu-item-container clock',
+ hexpand: true,
+ vpack: 'center',
+ hpack: 'fill',
+ child: Widget.Box({
+ hexpand: true,
+ vpack: 'center',
+ hpack: 'center',
+ class_name: 'clock-content-items',
+ children: military.bind('value').as((is24hr) => {
+ if (!is24hr) {
+ return [
+ Widget.Box({
+ hpack: 'center',
+ children: [
+ Widget.Label({
+ class_name: 'clock-content-time',
+ label: time.bind(),
+ }),
+ ],
+ }),
+ Widget.Box({
+ hpack: 'center',
+ children: [
+ Widget.Label({
+ vpack: 'end',
+ class_name: 'clock-content-period',
+ label: period.bind(),
+ }),
+ ],
+ }),
+ ];
+ }
+
+ return [
+ Widget.Box({
+ hpack: 'center',
+ children: [
+ Widget.Label({
+ class_name: 'clock-content-time',
+ label: militaryTime.bind(),
+ }),
+ ],
+ }),
+ ];
}),
- Widget.Box({
- hpack: "center",
- children: [
- Widget.Label({
- vpack: "end",
- class_name: "clock-content-period",
- label: period.bind(),
- }),
- ],
- }),
- ];
- }
-
- return [
- Widget.Box({
- hpack: "center",
- children: [
- Widget.Label({
- class_name: "clock-content-time",
- label: militaryTime.bind(),
- }),
- ],
- }),
- ];
- }),
- }),
- });
+ }),
+ });
};
export { TimeWidget };
diff --git a/modules/menus/calendar/weather/hourly/icon/index.ts b/modules/menus/calendar/weather/hourly/icon/index.ts
index 0f9517b..2c636c1 100644
--- a/modules/menus/calendar/weather/hourly/icon/index.ts
+++ b/modules/menus/calendar/weather/hourly/icon/index.ts
@@ -1,32 +1,43 @@
-import { Weather } from "lib/types/weather.js";
-import { Variable } from "types/variable.js";
-import icons from "../../../../../icons/index.js";
+import { Weather, WeatherIconTitle } from 'lib/types/weather.js';
+import { Variable } from 'types/variable.js';
+import { weatherIcons } from 'modules/icons/weather.js';
+import { isValidWeatherIconTitle } from 'globals/weather';
+import { BoxWidget } from 'lib/types/widget';
+import { getNextEpoch } from '../utils';
-export const HourlyIcon = (theWeather: Variable, getNextEpoch: any) => {
- return Widget.Icon({
- class_name: "hourly-weather-icon",
- icon: theWeather.bind("value").as((w) => {
- if (!Object.keys(w).length) {
- return "-";
- }
+export const HourlyIcon = (theWeather: Variable, hoursFromNow: number): BoxWidget => {
+ const getIconQuery = (wthr: Weather): WeatherIconTitle => {
+ const nextEpoch = getNextEpoch(wthr, hoursFromNow);
+ const weatherAtEpoch = wthr.forecast.forecastday[0].hour.find((h) => h.time_epoch === nextEpoch);
- const nextEpoch = getNextEpoch(w);
- const weatherAtEpoch = w.forecast.forecastday[0].hour.find(
- (h) => h.time_epoch === nextEpoch,
- );
+ if (weatherAtEpoch === undefined) {
+ return 'warning';
+ }
- let iconQuery = weatherAtEpoch?.condition.text
- .trim()
- .toLowerCase()
- .replaceAll(" ", "_")
- || "warning"
- ;
+ let iconQuery = weatherAtEpoch.condition.text.trim().toLowerCase().replaceAll(' ', '_');
- if (!weatherAtEpoch?.is_day && iconQuery === "partly_cloudy") {
- iconQuery = "partly_cloudy_night";
- }
+ if (!weatherAtEpoch?.is_day && iconQuery === 'partly_cloudy') {
+ iconQuery = 'partly_cloudy_night';
+ }
- return icons.weather[iconQuery];
+ if (isValidWeatherIconTitle(iconQuery)) {
+ return iconQuery;
+ } else {
+ return 'warning';
+ }
+ };
+
+ return Widget.Box({
+ hpack: 'center',
+ child: theWeather.bind('value').as((w) => {
+ const iconQuery = getIconQuery(w);
+ const weatherIcn = weatherIcons[iconQuery] || weatherIcons['warning'];
+
+ return Widget.Label({
+ hpack: 'center',
+ class_name: 'hourly-weather-icon txt-icon',
+ label: weatherIcn,
+ });
}),
});
};
diff --git a/modules/menus/calendar/weather/hourly/index.ts b/modules/menus/calendar/weather/hourly/index.ts
index 046bf92..0eb1982 100644
--- a/modules/menus/calendar/weather/hourly/index.ts
+++ b/modules/menus/calendar/weather/hourly/index.ts
@@ -1,44 +1,25 @@
-import { Weather } from "lib/types/weather";
-import { Variable } from "types/variable";
-import { HourlyIcon } from "./icon/index.js";
-import { HourlyTemp } from "./temperature/index.js";
-import { HourlyTime } from "./time/index.js";
+import { Weather } from 'lib/types/weather';
+import { Variable } from 'types/variable';
+import { HourlyIcon } from './icon/index.js';
+import { HourlyTemp } from './temperature/index.js';
+import { HourlyTime } from './time/index.js';
+import { BoxWidget } from 'lib/types/widget.js';
-export const Hourly = (theWeather: Variable) => {
+export const Hourly = (theWeather: Variable): BoxWidget => {
return Widget.Box({
vertical: false,
hexpand: true,
- hpack: "fill",
- class_name: "hourly-weather-container",
+ hpack: 'fill',
+ class_name: 'hourly-weather-container',
children: [1, 2, 3, 4].map((hoursFromNow) => {
- const getNextEpoch = (wthr: Weather) => {
- const currentEpoch = wthr.location.localtime_epoch;
- const epochAtHourStart = currentEpoch - (currentEpoch % 3600);
- let nextEpoch = 3600 * hoursFromNow + epochAtHourStart;
-
- const curHour = new Date(currentEpoch * 1000).getHours();
-
- /*
- * NOTE: Since the API is only capable of showing the current day; if
- * the hours left in the day are less than 4 (aka spilling into the next day),
- * then rewind to contain the prediction within the current day.
- */
- if (curHour > 19) {
- const hoursToRewind = curHour - 19;
- nextEpoch =
- 3600 * hoursFromNow + epochAtHourStart - hoursToRewind * 3600;
- }
- return nextEpoch;
- };
-
return Widget.Box({
- class_name: "hourly-weather-item",
+ class_name: 'hourly-weather-item',
hexpand: true,
vertical: true,
children: [
- HourlyTime(theWeather, getNextEpoch),
- HourlyIcon(theWeather, getNextEpoch),
- HourlyTemp(theWeather, getNextEpoch),
+ HourlyTime(theWeather, hoursFromNow),
+ HourlyIcon(theWeather, hoursFromNow),
+ HourlyTemp(theWeather, hoursFromNow),
],
});
}),
diff --git a/modules/menus/calendar/weather/hourly/temperature/index.ts b/modules/menus/calendar/weather/hourly/temperature/index.ts
index d649358..440c994 100644
--- a/modules/menus/calendar/weather/hourly/temperature/index.ts
+++ b/modules/menus/calendar/weather/hourly/temperature/index.ts
@@ -1,29 +1,27 @@
-import { Weather } from "lib/types/weather";
-import { Variable } from "types/variable";
-import options from "options";
+import { Weather } from 'lib/types/weather';
+import { Variable } from 'types/variable';
+import options from 'options';
+import Label from 'types/widgets/label';
+import { Child } from 'lib/types/widget';
+import { getNextEpoch } from '../utils';
const { unit } = options.menus.clock.weather;
-export const HourlyTemp = (theWeather: Variable, getNextEpoch: any) => {
+export const HourlyTemp = (theWeather: Variable, hoursFromNow: number): Label => {
return Widget.Label({
- class_name: "hourly-weather-temp",
- label: Utils.merge(
- [theWeather.bind("value"), unit.bind("value")],
- (wthr, unt) => {
- if (!Object.keys(wthr).length) {
- return "-";
- }
+ class_name: 'hourly-weather-temp',
+ label: Utils.merge([theWeather.bind('value'), unit.bind('value')], (wthr, unt) => {
+ if (!Object.keys(wthr).length) {
+ return '-';
+ }
- const nextEpoch = getNextEpoch(wthr);
- const weatherAtEpoch = wthr.forecast.forecastday[0].hour.find(
- (h) => h.time_epoch === nextEpoch,
- );
+ const nextEpoch = getNextEpoch(wthr, hoursFromNow);
+ const weatherAtEpoch = wthr.forecast.forecastday[0].hour.find((h) => h.time_epoch === nextEpoch);
- if (unt === "imperial") {
- return `${weatherAtEpoch ? Math.ceil(weatherAtEpoch.temp_f) : "-"}° F`;
- }
- return `${weatherAtEpoch ? Math.ceil(weatherAtEpoch.temp_c) : "-"}° C`;
- },
- ),
+ if (unt === 'imperial') {
+ return `${weatherAtEpoch ? Math.ceil(weatherAtEpoch.temp_f) : '-'}° F`;
+ }
+ return `${weatherAtEpoch ? Math.ceil(weatherAtEpoch.temp_c) : '-'}° C`;
+ }),
});
};
diff --git a/modules/menus/calendar/weather/hourly/time/index.ts b/modules/menus/calendar/weather/hourly/time/index.ts
index 48e2ebe..717eac4 100644
--- a/modules/menus/calendar/weather/hourly/time/index.ts
+++ b/modules/menus/calendar/weather/hourly/time/index.ts
@@ -1,18 +1,21 @@
-import { Weather } from "lib/types/weather";
-import { Variable } from "types/variable";
+import { Weather } from 'lib/types/weather';
+import { Child } from 'lib/types/widget';
+import { Variable } from 'types/variable';
+import Label from 'types/widgets/label';
+import { getNextEpoch } from '../utils';
-export const HourlyTime = (theWeather: Variable, getNextEpoch: any) => {
+export const HourlyTime = (theWeather: Variable, hoursFromNow: number): Label => {
return Widget.Label({
- class_name: "hourly-weather-time",
- label: theWeather.bind("value").as((w) => {
+ class_name: 'hourly-weather-time',
+ label: theWeather.bind('value').as((w) => {
if (!Object.keys(w).length) {
- return "-";
+ return '-';
}
- const nextEpoch = getNextEpoch(w);
+ const nextEpoch = getNextEpoch(w, hoursFromNow);
const dateAtEpoch = new Date(nextEpoch * 1000);
let hours = dateAtEpoch.getHours();
- const ampm = hours >= 12 ? "PM" : "AM";
+ const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12 || 12;
return `${hours}${ampm}`;
diff --git a/modules/menus/calendar/weather/hourly/utils.ts b/modules/menus/calendar/weather/hourly/utils.ts
new file mode 100644
index 0000000..13f1d53
--- /dev/null
+++ b/modules/menus/calendar/weather/hourly/utils.ts
@@ -0,0 +1,20 @@
+import { Weather } from 'lib/types/weather';
+
+export const getNextEpoch = (wthr: Weather, hoursFromNow: number): number => {
+ const currentEpoch = wthr.location.localtime_epoch;
+ const epochAtHourStart = currentEpoch - (currentEpoch % 3600);
+ let nextEpoch = 3600 * hoursFromNow + epochAtHourStart;
+
+ const curHour = new Date(currentEpoch * 1000).getHours();
+
+ /*
+ * NOTE: Since the API is only capable of showing the current day; if
+ * the hours left in the day are less than 4 (aka spilling into the next day),
+ * then rewind to contain the prediction within the current day.
+ */
+ if (curHour > 19) {
+ const hoursToRewind = curHour - 19;
+ nextEpoch = 3600 * hoursFromNow + epochAtHourStart - hoursToRewind * 3600;
+ }
+ return nextEpoch;
+};
diff --git a/modules/menus/calendar/weather/icon/index.ts b/modules/menus/calendar/weather/icon/index.ts
index ee74236..dff981a 100644
--- a/modules/menus/calendar/weather/icon/index.ts
+++ b/modules/menus/calendar/weather/icon/index.ts
@@ -1,19 +1,18 @@
-import { Weather } from "lib/types/weather";
-import { Variable } from "types/variable";
-import { getWeatherStatusIcon } from "globals/weather.js";
+import { Weather } from 'lib/types/weather';
+import { Variable } from 'types/variable';
+import { getWeatherStatusTextIcon } from 'globals/weather.js';
+import { BoxWidget } from 'lib/types/widget';
-export const TodayIcon = (theWeather: Variable) => {
+export const TodayIcon = (theWeather: Variable): BoxWidget => {
return Widget.Box({
- vpack: "center",
- hpack: "start",
- class_name: "calendar-menu-weather today icon container",
- children: [
- Widget.Icon({
- class_name: "calendar-menu-weather today icon",
- icon: theWeather.bind("value").as((v) => {
- return getWeatherStatusIcon(v);
- }),
+ vpack: 'center',
+ hpack: 'start',
+ class_name: 'calendar-menu-weather today icon container',
+ child: Widget.Label({
+ class_name: 'calendar-menu-weather today icon txt-icon',
+ label: theWeather.bind('value').as((w) => {
+ return getWeatherStatusTextIcon(w);
}),
- ],
+ }),
});
};
diff --git a/modules/menus/calendar/weather/index.ts b/modules/menus/calendar/weather/index.ts
index 58fc2ea..bf4a6bf 100644
--- a/modules/menus/calendar/weather/index.ts
+++ b/modules/menus/calendar/weather/index.ts
@@ -1,21 +1,22 @@
-import { TodayIcon } from "./icon/index.js";
-import { TodayStats } from "./stats/index.js";
-import { TodayTemperature } from "./temperature/index.js";
-import { Hourly } from "./hourly/index.js";
-import { globalWeatherVar } from "globals/weather.js";
+import { TodayIcon } from './icon/index.js';
+import { TodayStats } from './stats/index.js';
+import { TodayTemperature } from './temperature/index.js';
+import { Hourly } from './hourly/index.js';
+import { globalWeatherVar } from 'globals/weather.js';
+import { BoxWidget } from 'lib/types/widget.js';
-const WeatherWidget = () => {
+const WeatherWidget = (): BoxWidget => {
return Widget.Box({
- class_name: "calendar-menu-item-container weather",
+ class_name: 'calendar-menu-item-container weather',
child: Widget.Box({
- class_name: "weather-container-box",
+ class_name: 'weather-container-box',
setup: (self) => {
return (self.child = Widget.Box({
vertical: true,
hexpand: true,
children: [
Widget.Box({
- class_name: "calendar-menu-weather today",
+ class_name: 'calendar-menu-weather today',
hexpand: true,
children: [
TodayIcon(globalWeatherVar),
@@ -24,7 +25,7 @@ const WeatherWidget = () => {
],
}),
Widget.Separator({
- class_name: "menu-separator weather",
+ class_name: 'menu-separator weather',
}),
Hourly(globalWeatherVar),
],
diff --git a/modules/menus/calendar/weather/stats/index.ts b/modules/menus/calendar/weather/stats/index.ts
index d0e8d40..197032f 100644
--- a/modules/menus/calendar/weather/stats/index.ts
+++ b/modules/menus/calendar/weather/stats/index.ts
@@ -1,29 +1,30 @@
-import { Weather } from "lib/types/weather";
-import { Variable } from "types/variable";
-import options from "options";
-import { Unit } from "lib/types/options";
-import { getRainChance, getWindConditions } from "globals/weather";
+import { Weather } from 'lib/types/weather';
+import { Variable } from 'types/variable';
+import options from 'options';
+import { Unit } from 'lib/types/options';
+import { getRainChance, getWindConditions } from 'globals/weather';
+import { BoxWidget } from 'lib/types/widget';
const { unit } = options.menus.clock.weather;
-export const TodayStats = (theWeather: Variable) => {
+export const TodayStats = (theWeather: Variable): BoxWidget => {
return Widget.Box({
- class_name: "calendar-menu-weather today stats container",
- hpack: "end",
- vpack: "center",
+ class_name: 'calendar-menu-weather today stats container',
+ hpack: 'end',
+ vpack: 'center',
vertical: true,
children: [
Widget.Box({
- class_name: "weather wind",
+ class_name: 'weather wind',
children: [
Widget.Label({
- class_name: "weather wind icon txt-icon",
- label: "",
+ class_name: 'weather wind icon txt-icon',
+ label: '',
}),
Widget.Label({
- class_name: "weather wind label",
+ class_name: 'weather wind label',
label: Utils.merge(
- [theWeather.bind("value"), unit.bind("value")],
+ [theWeather.bind('value'), unit.bind('value')],
(wthr: Weather, unt: Unit) => {
return getWindConditions(wthr, unt);
},
@@ -32,19 +33,15 @@ export const TodayStats = (theWeather: Variable) => {
],
}),
Widget.Box({
- class_name: "weather precip",
+ class_name: 'weather precip',
children: [
Widget.Label({
- class_name: "weather precip icon txt-icon",
- label: "",
+ class_name: 'weather precip icon txt-icon',
+ label: '',
}),
Widget.Label({
- class_name: "weather precip label",
- label: theWeather
- .bind("value")
- .as(
- (v) => getRainChance(v),
- ),
+ class_name: 'weather precip label',
+ label: theWeather.bind('value').as((v) => getRainChance(v)),
}),
],
}),
diff --git a/modules/menus/calendar/weather/temperature/index.ts b/modules/menus/calendar/weather/temperature/index.ts
index 366b983..597a75c 100644
--- a/modules/menus/calendar/weather/temperature/index.ts
+++ b/modules/menus/calendar/weather/temperature/index.ts
@@ -1,43 +1,41 @@
-import { Weather } from "lib/types/weather";
-import { Variable } from "types/variable";
-import options from "options";
-import { getTemperature, getWeatherIcon } from "globals/weather";
+import { Weather } from 'lib/types/weather';
+import { Variable } from 'types/variable';
+import options from 'options';
+import { getTemperature, getWeatherIcon } from 'globals/weather';
+import { BoxWidget } from 'lib/types/widget';
const { unit } = options.menus.clock.weather;
-export const TodayTemperature = (theWeather: Variable) => {
+export const TodayTemperature = (theWeather: Variable): BoxWidget => {
return Widget.Box({
- hpack: "center",
- vpack: "center",
+ hpack: 'center',
+ vpack: 'center',
vertical: true,
children: [
Widget.Box({
hexpand: true,
- vpack: "center",
- class_name: "calendar-menu-weather today temp container",
+ vpack: 'center',
+ class_name: 'calendar-menu-weather today temp container',
vertical: false,
children: [
Widget.Box({
hexpand: true,
- hpack: "center",
+ hpack: 'center',
children: [
Widget.Label({
- class_name: "calendar-menu-weather today temp label",
- label: Utils.merge(
- [theWeather.bind("value"), unit.bind("value")],
- (wthr, unt) => {
- return getTemperature(wthr, unt);
- },
- ),
+ class_name: 'calendar-menu-weather today temp label',
+ label: Utils.merge([theWeather.bind('value'), unit.bind('value')], (wthr, unt) => {
+ return getTemperature(wthr, unt);
+ }),
}),
Widget.Label({
class_name: theWeather
- .bind("value")
+ .bind('value')
.as(
(v) =>
`calendar-menu-weather today temp label icon txt-icon ${getWeatherIcon(Math.ceil(v.current.temp_f)).color}`,
),
label: theWeather
- .bind("value")
+ .bind('value')
.as((v) => getWeatherIcon(Math.ceil(v.current.temp_f)).icon),
}),
],
@@ -45,18 +43,18 @@ export const TodayTemperature = (theWeather: Variable) => {
],
}),
Widget.Box({
- hpack: "center",
+ hpack: 'center',
child: Widget.Label({
max_width_chars: 17,
- truncate: "end",
+ truncate: 'end',
lines: 2,
class_name: theWeather
- .bind("value")
+ .bind('value')
.as(
(v) =>
`calendar-menu-weather today condition label ${getWeatherIcon(Math.ceil(v.current.temp_f)).color}`,
),
- label: theWeather.bind("value").as((v) => v.current.condition.text),
+ label: theWeather.bind('value').as((v) => v.current.condition.text),
}),
}),
],
diff --git a/modules/menus/dashboard/controls/index.ts b/modules/menus/dashboard/controls/index.ts
index 62684f7..44d4fa7 100644
--- a/modules/menus/dashboard/controls/index.ts
+++ b/modules/menus/dashboard/controls/index.ts
@@ -1,95 +1,91 @@
-const network = await Service.import("network");
-const bluetooth = await Service.import("bluetooth");
-const notifications = await Service.import("notifications");
-const audio = await Service.import("audio");
+import { BoxWidget } from 'lib/types/widget';
-const Controls = () => {
+const network = await Service.import('network');
+const bluetooth = await Service.import('bluetooth');
+const notifications = await Service.import('notifications');
+const audio = await Service.import('audio');
+
+const Controls = (): BoxWidget => {
return Widget.Box({
- class_name: "dashboard-card controls-container",
- hpack: "fill",
- vpack: "fill",
+ class_name: 'dashboard-card controls-container',
+ hpack: 'fill',
+ vpack: 'fill',
expand: true,
children: [
Widget.Button({
- tooltip_text: "Toggle Wifi",
+ tooltip_text: 'Toggle Wifi',
expand: true,
setup: (self) => {
self.hook(network, () => {
- return (self.class_name = `dashboard-button wifi ${!network.wifi.enabled ? "disabled" : ""}`);
+ return (self.class_name = `dashboard-button wifi ${!network.wifi.enabled ? 'disabled' : ''}`);
});
},
on_primary_click: () => network.toggleWifi(),
child: Widget.Label({
- class_name: "txt-icon",
+ class_name: 'txt-icon',
setup: (self) => {
self.hook(network, () => {
- return (self.label = network.wifi.enabled ? "" : "");
+ return (self.label = network.wifi.enabled ? '' : '');
});
},
}),
}),
Widget.Button({
- tooltip_text: "Toggle Bluetooth",
+ tooltip_text: 'Toggle Bluetooth',
expand: true,
class_name: bluetooth
- .bind("enabled")
- .as(
- (btOn) => `dashboard-button bluetooth ${!btOn ? "disabled" : ""}`,
- ),
+ .bind('enabled')
+ .as((btOn) => `dashboard-button bluetooth ${!btOn ? 'disabled' : ''}`),
on_primary_click: () => bluetooth.toggle(),
child: Widget.Label({
- class_name: "txt-icon",
- label: bluetooth.bind("enabled").as((btOn) => (btOn ? "" : "")),
+ class_name: 'txt-icon',
+ label: bluetooth.bind('enabled').as((btOn) => (btOn ? '' : '')),
}),
}),
Widget.Button({
- tooltip_text: "Toggle Notifications",
+ tooltip_text: 'Toggle Notifications',
expand: true,
class_name: notifications
- .bind("dnd")
- .as(
- (dnd) => `dashboard-button notifications ${dnd ? "disabled" : ""}`,
- ),
+ .bind('dnd')
+ .as((dnd) => `dashboard-button notifications ${dnd ? 'disabled' : ''}`),
on_primary_click: () => (notifications.dnd = !notifications.dnd),
child: Widget.Label({
- class_name: "txt-icon",
- label: notifications.bind("dnd").as((dnd) => (dnd ? "" : "")),
+ class_name: 'txt-icon',
+ label: notifications.bind('dnd').as((dnd) => (dnd ? '' : '')),
}),
}),
Widget.Button({
- tooltip_text: "Toggle Mute (Playback)",
+ tooltip_text: 'Toggle Mute (Playback)',
expand: true,
- on_primary_click: () =>
- (audio.speaker.is_muted = !audio.speaker.is_muted),
+ on_primary_click: () => (audio.speaker.is_muted = !audio.speaker.is_muted),
setup: (self) => {
self.hook(audio, () => {
- return (self.class_name = `dashboard-button playback ${audio.speaker.is_muted ? "disabled" : ""}`);
+ return (self.class_name = `dashboard-button playback ${audio.speaker.is_muted ? 'disabled' : ''}`);
});
},
child: Widget.Label({
- class_name: "txt-icon",
+ class_name: 'txt-icon',
setup: (self) => {
self.hook(audio, () => {
- return (self.label = audio.speaker.is_muted ? "" : "");
+ return (self.label = audio.speaker.is_muted ? '' : '');
});
},
}),
}),
Widget.Button({
- tooltip_text: "Toggle Mute (Microphone)",
+ tooltip_text: 'Toggle Mute (Microphone)',
expand: true,
- on_primary_click: () =>
- (audio.microphone.is_muted = !audio.microphone.is_muted),
+ on_primary_click: () => (audio.microphone.is_muted = !audio.microphone.is_muted),
setup: (self) => {
self.hook(audio, () => {
- return (self.class_name = `dashboard-button input ${audio.microphone.is_muted ? "disabled" : ""}`);
+ return (self.class_name = `dashboard-button input ${audio.microphone.is_muted ? 'disabled' : ''}`);
});
},
child: Widget.Label({
- class_name: "txt-icon",
+ class_name: 'txt-icon',
setup: (self) => {
self.hook(audio, () => {
- return (self.label = audio.microphone.is_muted ? "" : "");
+ return (self.label = audio.microphone.is_muted ? '' : '');
});
},
}),
diff --git a/modules/menus/dashboard/directories/index.ts b/modules/menus/dashboard/directories/index.ts
index 6841858..5b6aa11 100644
--- a/modules/menus/dashboard/directories/index.ts
+++ b/modules/menus/dashboard/directories/index.ts
@@ -1,68 +1,63 @@
-import options from "options";
+import { BoxWidget } from 'lib/types/widget';
+import options from 'options';
const { left, right } = options.menus.dashboard.directories;
-const Directories = () => {
+const Directories = (): BoxWidget => {
return Widget.Box({
- class_name: "dashboard-card directories-container",
- vpack: "fill",
- hpack: "fill",
+ class_name: 'dashboard-card directories-container',
+ vpack: 'fill',
+ hpack: 'fill',
expand: true,
children: [
Widget.Box({
vertical: true,
expand: true,
- class_name: "section right",
+ class_name: 'section right',
children: [
Widget.Button({
- hpack: "start",
+ hpack: 'start',
expand: true,
- class_name: "directory-link left top",
- on_primary_click: left.directory1.command
- .bind("value")
- .as((cmd) => {
- return () => {
- App.closeWindow("dashboardmenu");
- Utils.execAsync(cmd);
- };
- }),
+ class_name: 'directory-link left top',
+ on_primary_click: left.directory1.command.bind('value').as((cmd) => {
+ return () => {
+ App.closeWindow('dashboardmenu');
+ Utils.execAsync(cmd);
+ };
+ }),
child: Widget.Label({
- hpack: "start",
- label: left.directory1.label.bind("value"),
+ hpack: 'start',
+ label: left.directory1.label.bind('value'),
}),
}),
Widget.Button({
expand: true,
- hpack: "start",
- class_name: "directory-link left middle",
- on_primary_click: left.directory2.command
- .bind("value")
- .as((cmd) => {
- return () => {
- App.closeWindow("dashboardmenu");
- Utils.execAsync(cmd);
- };
- }),
+ hpack: 'start',
+ class_name: 'directory-link left middle',
+ on_primary_click: left.directory2.command.bind('value').as((cmd) => {
+ return () => {
+ App.closeWindow('dashboardmenu');
+ Utils.execAsync(cmd);
+ };
+ }),
child: Widget.Label({
- hpack: "start",
- label: left.directory2.label.bind("value"),
+ hpack: 'start',
+ label: left.directory2.label.bind('value'),
}),
}),
Widget.Button({
expand: true,
- hpack: "start",
- class_name: "directory-link left bottom",
- on_primary_click: left.directory3.command
- .bind("value")
- .as((cmd) => {
- return () => {
- App.closeWindow("dashboardmenu");
- Utils.execAsync(cmd);
- };
- }),
+ hpack: 'start',
+ class_name: 'directory-link left bottom',
+ on_primary_click: left.directory3.command.bind('value').as((cmd) => {
+ return () => {
+ App.closeWindow('dashboardmenu');
+ Utils.execAsync(cmd);
+ };
+ }),
child: Widget.Label({
- hpack: "start",
- label: left.directory3.label.bind("value"),
+ hpack: 'start',
+ label: left.directory3.label.bind('value'),
}),
}),
],
@@ -70,57 +65,51 @@ const Directories = () => {
Widget.Box({
vertical: true,
expand: true,
- class_name: "section left",
+ class_name: 'section left',
children: [
Widget.Button({
- hpack: "start",
+ hpack: 'start',
expand: true,
- class_name: "directory-link right top",
- on_primary_click: right.directory1.command
- .bind("value")
- .as((cmd) => {
- return () => {
- App.closeWindow("dashboardmenu");
- Utils.execAsync(cmd);
- };
- }),
+ class_name: 'directory-link right top',
+ on_primary_click: right.directory1.command.bind('value').as((cmd) => {
+ return () => {
+ App.closeWindow('dashboardmenu');
+ Utils.execAsync(cmd);
+ };
+ }),
child: Widget.Label({
- hpack: "start",
- label: right.directory1.label.bind("value"),
+ hpack: 'start',
+ label: right.directory1.label.bind('value'),
}),
}),
Widget.Button({
expand: true,
- hpack: "start",
- class_name: "directory-link right middle",
- on_primary_click: right.directory2.command
- .bind("value")
- .as((cmd) => {
- return () => {
- App.closeWindow("dashboardmenu");
- Utils.execAsync(cmd);
- };
- }),
+ hpack: 'start',
+ class_name: 'directory-link right middle',
+ on_primary_click: right.directory2.command.bind('value').as((cmd) => {
+ return () => {
+ App.closeWindow('dashboardmenu');
+ Utils.execAsync(cmd);
+ };
+ }),
child: Widget.Label({
- hpack: "start",
- label: right.directory2.label.bind("value"),
+ hpack: 'start',
+ label: right.directory2.label.bind('value'),
}),
}),
Widget.Button({
expand: true,
- hpack: "start",
- class_name: "directory-link right bottom",
- on_primary_click: right.directory3.command
- .bind("value")
- .as((cmd) => {
- return () => {
- App.closeWindow("dashboardmenu");
- Utils.execAsync(cmd);
- };
- }),
+ hpack: 'start',
+ class_name: 'directory-link right bottom',
+ on_primary_click: right.directory3.command.bind('value').as((cmd) => {
+ return () => {
+ App.closeWindow('dashboardmenu');
+ Utils.execAsync(cmd);
+ };
+ }),
child: Widget.Label({
- hpack: "start",
- label: right.directory3.label.bind("value"),
+ hpack: 'start',
+ label: right.directory3.label.bind('value'),
}),
}),
],
diff --git a/modules/menus/dashboard/index.ts b/modules/menus/dashboard/index.ts
index 538b7a7..ea37628 100644
--- a/modules/menus/dashboard/index.ts
+++ b/modules/menus/dashboard/index.ts
@@ -1,37 +1,33 @@
-import DropdownMenu from "../DropdownMenu.js";
-import { Profile } from "./profile/index.js";
-import { Shortcuts } from "./shortcuts/index.js";
-import { Controls } from "./controls/index.js";
-import { Stats } from "./stats/index.js";
-import { Directories } from "./directories/index.js";
+import DropdownMenu from '../shared/dropdown/index.js';
+import { Profile } from './profile/index.js';
+import { Shortcuts } from './shortcuts/index.js';
+import { Controls } from './controls/index.js';
+import { Stats } from './stats/index.js';
+import { Directories } from './directories/index.js';
+import Window from 'types/widgets/window.js';
+import { Attribute, Child } from 'lib/types/widget.js';
-export default () => {
- return DropdownMenu({
- name: "dashboardmenu",
- transition: "crossfade",
- child: Widget.Box({
- class_name: "dashboard-menu-content",
- css: "padding: 1px; margin: -1px;",
- vexpand: false,
- children: [
- Widget.Box({
- class_name: "dashboard-content-container",
- vertical: true,
- children: [
- Widget.Box({
- class_name: "dashboard-content-items",
- vertical: true,
- children: [
- Profile(),
- Shortcuts(),
- Controls(),
- Directories(),
- Stats(),
- ],
- }),
- ],
+export default (): Window => {
+ return DropdownMenu({
+ name: 'dashboardmenu',
+ transition: 'crossfade',
+ child: Widget.Box({
+ class_name: 'dashboard-menu-content',
+ css: 'padding: 1px; margin: -1px;',
+ vexpand: false,
+ children: [
+ Widget.Box({
+ class_name: 'dashboard-content-container',
+ vertical: true,
+ children: [
+ Widget.Box({
+ class_name: 'dashboard-content-items',
+ vertical: true,
+ children: [Profile(), Shortcuts(), Controls(), Directories(), Stats()],
+ }),
+ ],
+ }),
+ ],
}),
- ],
- }),
- });
+ });
};
diff --git a/modules/menus/dashboard/profile/index.ts b/modules/menus/dashboard/profile/index.ts
index d2d1673..9d2531a 100644
--- a/modules/menus/dashboard/profile/index.ts
+++ b/modules/menus/dashboard/profile/index.ts
@@ -1,58 +1,67 @@
-import icons from "../../../icons/index.js";
-import powermenu from "../../power/helpers/actions.js";
-import { PowerOptions } from "lib/types/options.js";
-import GdkPixbuf from "gi://GdkPixbuf";
+import powermenu from '../../power/helpers/actions.js';
+import { PowerOptions } from 'lib/types/options.js';
+import GdkPixbuf from 'gi://GdkPixbuf';
-import options from "options";
+import options from 'options';
+import { BoxWidget, Child } from 'lib/types/widget.js';
+import Label from 'types/widgets/label.js';
const { image, name } = options.menus.dashboard.powermenu.avatar;
const { confirmation, shutdown, logout, sleep, reboot } = options.menus.dashboard.powermenu;
-const Profile = () => {
- const handleClick = (action: PowerOptions) => {
+const Profile = (): BoxWidget => {
+ const handleClick = (action: PowerOptions): void => {
const actions = {
shutdown: shutdown.value,
reboot: reboot.value,
logout: logout.value,
sleep: sleep.value,
};
- App.closeWindow("dashboardmenu");
+ App.closeWindow('dashboardmenu');
if (!confirmation.value) {
- Utils.execAsync(actions[action])
- .catch((err) => console.error(`Failed to execute ${action} command. Error: ${err}`));
+ Utils.execAsync(actions[action]).catch((err) =>
+ console.error(`Failed to execute ${action} command. Error: ${err}`),
+ );
} else {
powermenu.action(action);
}
};
+ const getIconForButton = (txtIcon: string): Label => {
+ return Widget.Label({
+ className: 'txt-icon',
+ label: txtIcon,
+ });
+ };
+
return Widget.Box({
- class_name: "profiles-container",
- hpack: "fill",
+ class_name: 'profiles-container',
+ hpack: 'fill',
hexpand: true,
children: [
Widget.Box({
- class_name: "profile-picture-container dashboard-card",
+ class_name: 'profile-picture-container dashboard-card',
hexpand: true,
vertical: true,
children: [
Widget.Box({
- hpack: "center",
- class_name: "profile-picture",
- css: image.bind("value").as(i => {
+ hpack: 'center',
+ class_name: 'profile-picture',
+ css: image.bind('value').as((i) => {
try {
GdkPixbuf.Pixbuf.new_from_file(i);
- return `background-image: url("${i}")`
+ return `background-image: url("${i}")`;
} catch {
- return `background-image: url("${App.configDir}/assets/hyprpanel.png")`
+ return `background-image: url("${App.configDir}/assets/hyprpanel.png")`;
}
}),
}),
Widget.Label({
- hpack: "center",
- class_name: "profile-name",
- label: name.bind("value").as((v) => {
- if (v === "system") {
- return Utils.exec("bash -c whoami");
+ hpack: 'center',
+ class_name: 'profile-name',
+ label: name.bind('value').as((v) => {
+ if (v === 'system') {
+ return Utils.exec('bash -c whoami');
}
return v;
}),
@@ -60,37 +69,37 @@ const Profile = () => {
],
}),
Widget.Box({
- class_name: "power-menu-container dashboard-card",
+ class_name: 'power-menu-container dashboard-card',
vertical: true,
vexpand: true,
children: [
Widget.Button({
- class_name: "dashboard-button shutdown",
- on_clicked: () => handleClick("shutdown"),
- tooltip_text: "Shut Down",
+ class_name: 'dashboard-button shutdown',
+ on_clicked: () => handleClick('shutdown'),
+ tooltip_text: 'Shut Down',
vexpand: true,
- child: Widget.Icon(icons.powermenu.shutdown),
+ child: getIconForButton(''),
}),
Widget.Button({
- class_name: "dashboard-button restart",
- on_clicked: () => handleClick("reboot"),
- tooltip_text: "Restart",
+ class_name: 'dashboard-button restart',
+ on_clicked: () => handleClick('reboot'),
+ tooltip_text: 'Restart',
vexpand: true,
- child: Widget.Icon(icons.powermenu.reboot),
+ child: getIconForButton(''),
}),
Widget.Button({
- class_name: "dashboard-button lock",
- on_clicked: () => handleClick("logout"),
- tooltip_text: "Log Out",
+ class_name: 'dashboard-button lock',
+ on_clicked: () => handleClick('logout'),
+ tooltip_text: 'Log Out',
vexpand: true,
- child: Widget.Icon(icons.powermenu.logout),
+ child: getIconForButton(''),
}),
Widget.Button({
- class_name: "dashboard-button sleep",
- on_clicked: () => handleClick("sleep"),
- tooltip_text: "Sleep",
+ class_name: 'dashboard-button sleep',
+ on_clicked: () => handleClick('sleep'),
+ tooltip_text: 'Sleep',
vexpand: true,
- child: Widget.Icon(icons.powermenu.sleep),
+ child: getIconForButton(''),
}),
],
}),
diff --git a/modules/menus/dashboard/shortcuts/index.ts b/modules/menus/dashboard/shortcuts/index.ts
index 3db359a..ce00aae 100644
--- a/modules/menus/dashboard/shortcuts/index.ts
+++ b/modules/menus/dashboard/shortcuts/index.ts
@@ -1,24 +1,28 @@
-const hyprland = await Service.import("hyprland");
-import options from "options";
-import { Variable as VarType } from "types/variable";
+const hyprland = await Service.import('hyprland');
+import { Attribute, BoxWidget, Child } from 'lib/types/widget';
+import options from 'options';
+import { Variable as VarType } from 'types/variable';
+import Box from 'types/widgets/box';
+import Button from 'types/widgets/button';
+import Label from 'types/widgets/label';
const { left, right } = options.menus.dashboard.shortcuts;
-const Shortcuts = () => {
+const Shortcuts = (): BoxWidget => {
const isRecording = Variable(false, {
poll: [
1000,
`${App.configDir}/services/screen_record.sh status`,
- (out) => {
- if (out === "recording") {
+ (out): boolean => {
+ if (out === 'recording') {
return true;
}
return false;
},
],
});
- const handleClick = (action: any, tOut: number = 250) => {
- App.closeWindow("dashboardmenu");
+ const handleClick = (action: string, tOut: number = 250): void => {
+ App.closeWindow('dashboardmenu');
setTimeout(() => {
Utils.execAsync(action)
@@ -30,8 +34,8 @@ const Shortcuts = () => {
};
const recordingDropdown = Widget.Menu({
- class_name: "dropdown recording",
- hpack: "fill",
+ class_name: 'dropdown recording',
+ hpack: 'fill',
hexpand: true,
setup: (self) => {
self.hook(hyprland, () => {
@@ -39,26 +43,26 @@ const Shortcuts = () => {
return Widget.MenuItem({
label: `Display ${mon.name}`,
on_activate: () => {
- App.closeWindow("dashboardmenu");
- Utils.execAsync(
- `${App.configDir}/services/screen_record.sh start ${mon.name}`,
- ).catch((err) => console.error(err));
+ App.closeWindow('dashboardmenu');
+ Utils.execAsync(`${App.configDir}/services/screen_record.sh start ${mon.name}`).catch(
+ (err) => console.error(err),
+ );
},
});
});
// NOTE: This is disabled since window recording isn't available on wayland
- const apps = hyprland.clients.map((clt) => {
- return Widget.MenuItem({
- label: `${clt.class.charAt(0).toUpperCase() + clt.class.slice(1)} (Workspace ${clt.workspace.name})`,
- on_activate: () => {
- App.closeWindow("dashboardmenu");
- Utils.execAsync(
- `${App.configDir}/services/screen_record.sh start ${clt.focusHistoryID}`,
- ).catch((err) => console.error(err));
- },
- });
- });
+ // const apps = hyprland.clients.map((clt) => {
+ // return Widget.MenuItem({
+ // label: `${clt.class.charAt(0).toUpperCase() + clt.class.slice(1)} (Workspace ${clt.workspace.name})`,
+ // on_activate: () => {
+ // App.closeWindow('dashboardmenu');
+ // Utils.execAsync(
+ // `${App.configDir}/services/screen_record.sh start ${clt.focusHistoryID}`,
+ // ).catch((err) => console.error(err));
+ // },
+ // });
+ // });
return (self.children = [
...displays,
@@ -85,15 +89,15 @@ const Shortcuts = () => {
type Shortcut = ShortcutFixed | ShortcutVariable;
- const cmdLn = (sCut: ShortcutVariable) => {
- return sCut.command.value.length > 0
+ const cmdLn = (sCut: ShortcutVariable): boolean => {
+ return sCut.command.value.length > 0;
};
const leftCardHidden = Variable(
- !(cmdLn(left.shortcut1) || cmdLn(left.shortcut2) || cmdLn(left.shortcut3) || cmdLn(left.shortcut4))
+ !(cmdLn(left.shortcut1) || cmdLn(left.shortcut2) || cmdLn(left.shortcut3) || cmdLn(left.shortcut4)),
);
- function createButton(shortcut: Shortcut, className: string) {
+ const createButton = (shortcut: Shortcut, className: string): Button