hyprpanel
This commit is contained in:
1 parent
10080a83ee
commit
5151ac24da
322 files changed
+38276
No files matched your search
@@ -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',
|
||||
]);
|
||||
@@ -0,0 +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',
|
||||
} as const;
|
||||
|
||||
export default {
|
||||
missing: 'image-missing-symbolic',
|
||||
nix: {
|
||||
nix: 'nix-snowflake-symbolic',
|
||||
},
|
||||
app: {
|
||||
terminal: 'terminal-symbolic',
|
||||
},
|
||||
fallback: {
|
||||
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',
|
||||
arrow: {
|
||||
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',
|
||||
},
|
||||
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',
|
||||
},
|
||||
type: {
|
||||
headset: 'audio-headphones-symbolic',
|
||||
speaker: 'audio-speakers-symbolic',
|
||||
card: 'audio-card-symbolic',
|
||||
},
|
||||
mixer: 'mixer-symbolic',
|
||||
},
|
||||
powerprofile: {
|
||||
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',
|
||||
},
|
||||
mode: {
|
||||
Integrated: 'processor-symbolic',
|
||||
Hybrid: 'controller-symbolic',
|
||||
},
|
||||
},
|
||||
battery: {
|
||||
charging: 'battery-flash-symbolic',
|
||||
warning: 'battery-empty-symbolic',
|
||||
},
|
||||
bluetooth: {
|
||||
enabled: 'bluetooth-active-symbolic',
|
||||
disabled: 'bluetooth-disabled-symbolic',
|
||||
},
|
||||
brightness: {
|
||||
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',
|
||||
},
|
||||
recorder: {
|
||||
recording: 'media-record-symbolic',
|
||||
},
|
||||
notifications: {
|
||||
noisy: 'org.gnome.Settings-notifications-symbolic',
|
||||
silent: 'notifications-disabled-symbolic',
|
||||
message: 'chat-bubbles-symbolic',
|
||||
},
|
||||
trash: {
|
||||
full: 'user-trash-full-symbolic',
|
||||
empty: 'user-trash-symbolic',
|
||||
},
|
||||
mpris: {
|
||||
shuffle: {
|
||||
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',
|
||||
},
|
||||
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',
|
||||
},
|
||||
color: {
|
||||
dark: 'dark-mode-symbolic',
|
||||
light: 'light-mode-symbolic',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,147 @@
|
||||
import { isHexColor } from 'globals/variables';
|
||||
import { Variable } from 'resource:///com/github/Aylur/ags/variable.js';
|
||||
import { MkOptionsResult } from './types/options';
|
||||
|
||||
type OptProps = {
|
||||
persistent?: boolean;
|
||||
};
|
||||
|
||||
export class Opt<T = unknown> extends Variable<T> {
|
||||
static {
|
||||
Service.register(this);
|
||||
}
|
||||
|
||||
constructor(initial: T, { persistent = false }: OptProps = {}) {
|
||||
super(initial);
|
||||
this.initial = initial;
|
||||
this.persistent = persistent;
|
||||
}
|
||||
|
||||
initial: T;
|
||||
id = '';
|
||||
persistent: boolean;
|
||||
toString(): string {
|
||||
return `${this.value}`;
|
||||
}
|
||||
toJSON(): string {
|
||||
return `opt:${this.value}`;
|
||||
}
|
||||
|
||||
getValue = (): T => {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
reset(): string | undefined {
|
||||
if (this.persistent) return;
|
||||
|
||||
if (JSON.stringify(this.value) !== JSON.stringify(this.initial)) {
|
||||
this.value = this.initial;
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
doResetColor(): string | undefined {
|
||||
if (this.persistent) return;
|
||||
|
||||
const isColor = isHexColor(this.value as string);
|
||||
if (JSON.stringify(this.value) !== JSON.stringify(this.initial) && isColor) {
|
||||
this.value = this.initial;
|
||||
return this.id;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export const opt = <T>(initial: T, opts?: OptProps): Opt<T> => new Opt(initial, opts);
|
||||
|
||||
const getOptions = (object: Record<string, unknown>, path = ''): Opt[] => {
|
||||
return Object.keys(object).flatMap((key) => {
|
||||
const obj = object[key];
|
||||
const id = path ? path + '.' + key : key;
|
||||
|
||||
if (obj instanceof Variable) {
|
||||
const optValue = obj as Opt;
|
||||
optValue.id = id;
|
||||
return optValue;
|
||||
}
|
||||
|
||||
if (typeof obj === 'object' && obj !== null) {
|
||||
return getOptions(obj as Record<string, unknown>, id); // Recursively process nested objects
|
||||
}
|
||||
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
export function mkOptions<T extends object>(
|
||||
cacheFile: string,
|
||||
object: T,
|
||||
confFile: string = 'config.json',
|
||||
): T & MkOptionsResult {
|
||||
for (const opt of getOptions(object as Record<string, unknown>)) opt.init(cacheFile);
|
||||
|
||||
Utils.ensureDirectory(cacheFile.split('/').slice(0, -1).join('/'));
|
||||
|
||||
const configFile = `${TMP}/${confFile}`;
|
||||
const values = getOptions(object as Record<string, unknown>).reduce(
|
||||
(obj, { id, value }) => ({ [id]: value, ...obj }),
|
||||
{},
|
||||
);
|
||||
Utils.writeFileSync(JSON.stringify(values, null, 2), configFile);
|
||||
Utils.monitorFile(configFile, () => {
|
||||
const cache = JSON.parse(Utils.readFile(configFile) || '{}');
|
||||
for (const opt of getOptions(object as Record<string, unknown>)) {
|
||||
if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value)) opt.value = cache[opt.id];
|
||||
}
|
||||
});
|
||||
|
||||
function sleep(ms = 0): Promise<T> {
|
||||
return new Promise((r) => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
const reset = async (
|
||||
[opt, ...list] = getOptions(object as Record<string, unknown>),
|
||||
id = opt?.reset(),
|
||||
): Promise<Array<string>> => {
|
||||
if (!opt) return sleep().then(() => []);
|
||||
|
||||
return id ? [id, ...(await sleep(50).then(() => reset(list)))] : await sleep().then(() => reset(list));
|
||||
};
|
||||
|
||||
const resetTheme = async (
|
||||
[opt, ...list] = getOptions(object as Record<string, unknown>),
|
||||
id = opt?.doResetColor(),
|
||||
): Promise<Array<string>> => {
|
||||
if (!opt) return sleep().then(() => []);
|
||||
|
||||
return id
|
||||
? [id, ...(await sleep(50).then(() => resetTheme(list)))]
|
||||
: await sleep().then(() => resetTheme(list));
|
||||
};
|
||||
|
||||
return Object.assign(object, {
|
||||
configFile,
|
||||
array: () => getOptions(object as Record<string, unknown>),
|
||||
async reset() {
|
||||
return (await reset()).join('\n');
|
||||
},
|
||||
async resetTheme() {
|
||||
return (await resetTheme()).join('\n');
|
||||
},
|
||||
handler(deps: string[], callback: () => void) {
|
||||
for (const opt of getOptions(object as Record<string, unknown>)) {
|
||||
if (deps.some((i) => opt.id.startsWith(i))) opt.connect('changed', callback);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import GLib from 'gi://GLib?version=2.0';
|
||||
|
||||
declare global {
|
||||
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`);
|
||||
@@ -0,0 +1,28 @@
|
||||
import { MprisPlayer } from 'types/service/mpris';
|
||||
const mpris = await Service.import('mpris');
|
||||
|
||||
export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]): MprisPlayer => {
|
||||
const statusOrder = {
|
||||
Playing: 1,
|
||||
Paused: 2,
|
||||
Stopped: 3,
|
||||
};
|
||||
|
||||
if (mpris.players.length === 0) {
|
||||
return mpris.players[0];
|
||||
}
|
||||
|
||||
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 nextPlayerUp = mpris.players.sort(
|
||||
(a: MprisPlayer, b: MprisPlayer) => statusOrder[a.play_back_status] - statusOrder[b.play_back_status],
|
||||
)[0];
|
||||
|
||||
if (isPlaying || !playerStillExists) {
|
||||
return nextPlayerUp;
|
||||
}
|
||||
|
||||
return activePlayer;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
export type InputDevices = Button<Box<Box<Label<Attribute>, Attribute>, Attribute>, Attribute>[];
|
||||
|
||||
type DummyDevices = Button<Box<Box<Label<Attribute>, Attribute>, Attribute>, Attribute>[];
|
||||
type RealPlaybackDevices = Button<Box<Box<Label<Attribute>, Attribute>, Attribute>, Attribute>[];
|
||||
export type PlaybackDevices = DummyDevices | RealPlaybackDevices;
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
import { Binding, Connectable } from 'types/service';
|
||||
import { Variable } from 'types/variable';
|
||||
import Box from 'types/widgets/box';
|
||||
import Button, { ButtonProps } from 'types/widgets/button';
|
||||
import Label from 'types/widgets/label';
|
||||
import { Attribute, Child } from './widget';
|
||||
|
||||
export type BarBoxChild = {
|
||||
component: Box<Gtk.Widget, unknown>;
|
||||
isVisible?: boolean;
|
||||
isVis?: Variable<boolean>;
|
||||
boxClass: string;
|
||||
tooltip_text?: string | Binding<string>;
|
||||
props: ButtonProps;
|
||||
};
|
||||
|
||||
export type SelfButton = Button<Child, Attribute>;
|
||||
|
||||
export type BoxHook = (self: Box<Gtk.Widget, Gtk.Widget>) => void;
|
||||
export type LabelHook = (self: Label<Gtk.Widget>) => void;
|
||||
|
||||
export type Module = {
|
||||
icon?: string | Binding<string>;
|
||||
textIcon?: string | Binding<string>;
|
||||
label?: string | Binding<string>;
|
||||
labelHook?: LabelHook;
|
||||
boundLabel?: string;
|
||||
tooltipText?: string | Binding<string>;
|
||||
boxClass: string;
|
||||
props?: ButtonProps;
|
||||
showLabel?: boolean;
|
||||
showLabelBinding?: Binding;
|
||||
hook?: BoxHook;
|
||||
connection?: Binding<Connectable>;
|
||||
};
|
||||
|
||||
export type ResourceLabelType = 'used/total' | 'used' | 'percentage' | 'free';
|
||||
|
||||
export type NetstatLabelType = 'full' | 'in' | 'out';
|
||||
export type RateUnit = 'GiB' | 'MiB' | 'KiB' | 'auto';
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
export type GenericFunction<T, P extends unknown[] = unknown[]> = (...args: P) => T;
|
||||
|
||||
export type GenericResourceMetrics = {
|
||||
total: number;
|
||||
used: number;
|
||||
percentage: number;
|
||||
};
|
||||
|
||||
type GenericResourceData = ResourceUsage & {
|
||||
free: number;
|
||||
};
|
||||
|
||||
export type Postfix = 'TiB' | 'GiB' | 'MiB' | 'KiB' | 'B';
|
||||
@@ -0,0 +1,32 @@
|
||||
import { layoutMap } from 'customModules/kblayout/layouts';
|
||||
|
||||
export type KbLabelType = 'layout' | 'code';
|
||||
|
||||
export type HyprctlKeyboard = {
|
||||
address: string;
|
||||
name: string;
|
||||
rules: string;
|
||||
model: string;
|
||||
layout: string;
|
||||
variant: string;
|
||||
options: string;
|
||||
active_keymap: string;
|
||||
main: boolean;
|
||||
};
|
||||
|
||||
export type HyprctlMouse = {
|
||||
address: string;
|
||||
name: string;
|
||||
defaultSpeed: number;
|
||||
};
|
||||
|
||||
export type HyprctlDeviceLayout = {
|
||||
mice: HyprctlMouse[];
|
||||
keyboards: HyprctlKeyboard[];
|
||||
tablets: unknown[];
|
||||
touch: unknown[];
|
||||
switches: unknown[];
|
||||
};
|
||||
|
||||
export type LayoutKeys = keyof typeof layoutMap;
|
||||
export type LayoutValues = (typeof layoutMap)[LayoutKeys];
|
||||
@@ -0,0 +1,4 @@
|
||||
export type NetworkResourceData = {
|
||||
in: string;
|
||||
out: string;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Binding } from 'lib/utils';
|
||||
|
||||
export type InputHandlerEvents = {
|
||||
onPrimaryClick?: Binding;
|
||||
onSecondaryClick?: Binding;
|
||||
onMiddleClick?: Binding;
|
||||
onScrollUp?: Binding;
|
||||
onScrollDown?: Binding;
|
||||
};
|
||||
|
||||
export type RunAsyncCommand = (cmd: string, args: EventArgs, fn?: (output: string) => void) => void;
|
||||
@@ -0,0 +1,5 @@
|
||||
import { NetstatLabelType, ResourceLabelType } from '../bar';
|
||||
|
||||
export const LABEL_TYPES: ResourceLabelType[] = ['used/total', 'used', 'free', 'percentage'];
|
||||
|
||||
export const NETWORK_LABEL_TYPES: NetstatLabelType[] = ['full', 'in', 'out'];
|
||||
@@ -0,0 +1,10 @@
|
||||
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 ${dataType}/s`, out: `0 ${dataType}/s` };
|
||||
};
|
||||
@@ -0,0 +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',
|
||||
} as const;
|
||||
File diff suppressed because it is too large.
Load diff
+12
@@ -0,0 +1,12 @@
|
||||
import { WindowProps } from 'types/widgets/window';
|
||||
import { GtkWidget, Transition } from './widget';
|
||||
import { Binding } from 'types/service';
|
||||
|
||||
export type DropdownMenuProps = {
|
||||
name: string;
|
||||
child: GtkWidget;
|
||||
layout?: string;
|
||||
transition?: Transition | Binding<Transition>;
|
||||
exclusivity?: Exclusivity;
|
||||
fixed?: boolean;
|
||||
} & WindowProps;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export type Config = {
|
||||
[key: string]: string | number | boolean | object;
|
||||
};
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
export type MousePos = {
|
||||
source: string;
|
||||
pos: number[];
|
||||
};
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
export type GPU_Stat_Process = {
|
||||
username: string;
|
||||
command: string;
|
||||
full_command: string[];
|
||||
gpu_memory_usage: number;
|
||||
cpu_percent: number;
|
||||
cpu_memory_usage: number;
|
||||
pid: number;
|
||||
};
|
||||
|
||||
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;
|
||||
processes: Process[];
|
||||
};
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
export type LoopStatus = 'none' | 'track' | 'playlist';
|
||||
export type PlaybackStatus = 'playing' | 'paused' | 'stopped';
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
import { WIFI_STATUS_MAP } from 'globals/network';
|
||||
|
||||
export type AccessPoint = {
|
||||
bssid: string | null;
|
||||
address: string | null;
|
||||
lastSeen: number;
|
||||
ssid: string | null;
|
||||
active: boolean;
|
||||
strength: number;
|
||||
frequency: number;
|
||||
iconName: string | undefined;
|
||||
};
|
||||
|
||||
export type WifiStatus = keyof typeof WIFI_STATUS_MAP;
|
||||
|
||||
export type WifiIcon = '' | '' | '' | '' | '' | '' | '' | '' | '' | '' | '';
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import icons from 'modules/icons/index';
|
||||
|
||||
export interface NotificationArgs {
|
||||
appName?: string;
|
||||
body?: string;
|
||||
iconName?: string;
|
||||
id?: number;
|
||||
summary?: string;
|
||||
urgency?: Urgency;
|
||||
category?: string;
|
||||
timeout?: number;
|
||||
transient?: boolean;
|
||||
}
|
||||
|
||||
export type NotificationIcon = keyof typeof icons.notifications;
|
||||
Vendored
+217
@@ -0,0 +1,217 @@
|
||||
import { Opt } from 'lib/option';
|
||||
import { Variable } from 'types/variable';
|
||||
import { defaultColorMap } from './defaults/options';
|
||||
|
||||
export type MkOptionsResult = {
|
||||
configFile: string;
|
||||
array: () => Opt[];
|
||||
reset: () => Promise<string>;
|
||||
resetTheme: () => Promise<string>;
|
||||
handler: (deps: string[], callback: () => void) => void;
|
||||
};
|
||||
|
||||
export type RecursiveOptionsObject = {
|
||||
[key: string]: RecursiveOptionsObject | Opt<string> | Opt<number> | Opt<boolean>;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
export type RowProps<T> = {
|
||||
opt: Opt<T>;
|
||||
title: string;
|
||||
note?: string;
|
||||
type?:
|
||||
| 'number'
|
||||
| 'color'
|
||||
| 'float'
|
||||
| 'object'
|
||||
| 'string'
|
||||
| 'enum'
|
||||
| 'boolean'
|
||||
| 'img'
|
||||
| 'wallpaper'
|
||||
| 'export'
|
||||
| 'import'
|
||||
| 'config_import'
|
||||
| 'font';
|
||||
enums?: T[];
|
||||
max?: number;
|
||||
min?: number;
|
||||
disabledBinding?: Variable<boolean>;
|
||||
exportData?: ThemeExportData;
|
||||
subtitle?: string | VarType<string> | Opt;
|
||||
subtitleLink?: string;
|
||||
dependencies?: string[];
|
||||
increment?: number;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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';
|
||||
|
||||
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';
|
||||
|
||||
export type ColorMapKey = keyof typeof defaultColorMap;
|
||||
export type ColorMapValue = (typeof defaultColorMap)[ColorMapKey];
|
||||
|
||||
export type ScalingPriority = 'gdk' | 'hyprland' | 'both';
|
||||
+35
@@ -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: Widget;
|
||||
layout?: Layouts;
|
||||
transition?: Transition | Binding<Transition>;
|
||||
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';
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
export type Action = 'sleep' | 'reboot' | 'logout' | 'shutdown';
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import PowerProfiles from 'types/service/powerprofiles.js';
|
||||
|
||||
export type PowerProfiles = InstanceType<typeof PowerProfiles>;
|
||||
export type PowerProfile = 'power-saver' | 'balanced' | 'performance';
|
||||
export type PowerProfileObject = {
|
||||
[key: string]: string;
|
||||
};
|
||||
Whitespace-only changes.
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
import { substitutes } from 'lib/icons';
|
||||
import { EventArgs } from './widget';
|
||||
|
||||
type SubstituteKeys = keyof typeof substitutes;
|
||||
|
||||
export type ThrottleFn = (cmd: string, args: EventArgs, fn?: (output: string) => void) => void;
|
||||
export type ThrottleFnCallback = ((output: string) => void) | undefined;
|
||||
+1
@@ -0,0 +1 @@
|
||||
export type Bind = OriginalBinding<GObject.Object, keyof Props<GObject.Object>, unknown>;
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
export type VolumeIcons = {
|
||||
[index: number]: string;
|
||||
};
|
||||
Vendored
+118
@@ -0,0 +1,118 @@
|
||||
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;
|
||||
last_updated?: string;
|
||||
temp_c: number;
|
||||
temp_f: number;
|
||||
is_day: number;
|
||||
condition: Condition;
|
||||
wind_mph: number;
|
||||
wind_kph: number;
|
||||
wind_degree: number;
|
||||
wind_dir: string;
|
||||
pressure_mb: number;
|
||||
pressure_in: number;
|
||||
precip_mm: number;
|
||||
precip_in: number;
|
||||
humidity: number;
|
||||
cloud: number;
|
||||
feelslike_c: number;
|
||||
feelslike_f: number;
|
||||
windchill_c: number;
|
||||
windchill_f: number;
|
||||
heatindex_c: number;
|
||||
heatindex_f: number;
|
||||
dewpoint_c: number;
|
||||
dewpoint_f: number;
|
||||
vis_km: number;
|
||||
vis_miles: number;
|
||||
uv: number;
|
||||
gust_mph: number;
|
||||
gust_kph: number;
|
||||
time_epoch?: number;
|
||||
time?: string;
|
||||
snow_cm?: number;
|
||||
will_it_rain?: number;
|
||||
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;
|
||||
date_epoch: number;
|
||||
day: Day;
|
||||
astro: Astro;
|
||||
hour: Current[];
|
||||
};
|
||||
|
||||
export type Astro = {
|
||||
sunrise: string;
|
||||
sunset: string;
|
||||
moonrise: string;
|
||||
moonset: string;
|
||||
moon_phase: string;
|
||||
moon_illumination: number;
|
||||
is_moon_up: number;
|
||||
is_sun_up: number;
|
||||
};
|
||||
|
||||
export type Day = {
|
||||
maxtemp_c: number;
|
||||
maxtemp_f: number;
|
||||
mintemp_c: number;
|
||||
mintemp_f: number;
|
||||
avgtemp_c: number;
|
||||
avgtemp_f: number;
|
||||
maxwind_mph: number;
|
||||
maxwind_kph: number;
|
||||
totalprecip_mm: number;
|
||||
totalprecip_in: number;
|
||||
totalsnow_cm: number;
|
||||
avgvis_km: number;
|
||||
avgvis_miles: number;
|
||||
avghumidity: number;
|
||||
daily_will_it_rain: number;
|
||||
daily_chance_of_rain: number;
|
||||
daily_will_it_snow: number;
|
||||
daily_chance_of_snow: number;
|
||||
condition: Condition;
|
||||
uv: number;
|
||||
};
|
||||
|
||||
export type Location = {
|
||||
name: string;
|
||||
region: string;
|
||||
country: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
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];
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
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 Layouts =
|
||||
| 'center'
|
||||
| 'top'
|
||||
| 'top-right'
|
||||
| 'top-center'
|
||||
| 'top-left'
|
||||
| 'bottom-left'
|
||||
| 'bottom-center'
|
||||
| 'bottom-right';
|
||||
|
||||
export type Attribute = unknown;
|
||||
export type Child = Gtk.Widget;
|
||||
export type GtkWidget = Gtk.Widget;
|
||||
export type BoxWidget = Box<GtkWidget, Child>;
|
||||
|
||||
export type GButton = Gtk.Button;
|
||||
export type GBox = Gtk.Box;
|
||||
export type GLabel = Gtk.Label;
|
||||
export type GCenterBox = Gtk.Box;
|
||||
|
||||
export type EventHandler<Self> = (self: Self, event: Gdk.Event) => boolean | unknown;
|
||||
export type EventArgs = { clicked: Button<Child, Attribute>; event: Gdk.Event };
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
export type WorkspaceRule = {
|
||||
workspaceString: string;
|
||||
monitor: string;
|
||||
};
|
||||
|
||||
export type WorkspaceMap = {
|
||||
[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;
|
||||
@@ -0,0 +1,195 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { type Application } from 'types/service/applications';
|
||||
import { NotificationAnchor } from './types/options';
|
||||
import { OSDAnchor } from 'lib/types/options';
|
||||
import icons, { substitutes } from './icons';
|
||||
import Gtk from 'gi://Gtk?version=3.0';
|
||||
import Gdk from 'gi://Gdk';
|
||||
import GLib from 'gi://GLib?version=2.0';
|
||||
import GdkPixbuf from 'gi://GdkPixbuf';
|
||||
import { NotificationArgs } from 'types/utils/notify';
|
||||
import { SubstituteKeys } from './types/utils';
|
||||
import { Window } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||
import { namedColors } from './constants/colors';
|
||||
|
||||
export type Binding<T> = import('types/service').Binding<any, any, T>;
|
||||
|
||||
/**
|
||||
* @returns substitute icon || name || fallback icon
|
||||
*/
|
||||
export function icon(name: string | null, fallback = icons.missing): string {
|
||||
const validateSubstitute = (name: string): name is SubstituteKeys => name in substitutes;
|
||||
|
||||
if (!name) return fallback || '';
|
||||
|
||||
if (GLib.file_test(name, GLib.FileTest.EXISTS)) return name;
|
||||
|
||||
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[]): Promise<string> {
|
||||
const cmd =
|
||||
typeof strings === 'string' ? strings : strings.flatMap((str, i) => str + `${values[i] ?? ''}`).join('');
|
||||
|
||||
return Utils.execAsync(['bash', '-c', cmd]).catch((err) => {
|
||||
console.error(cmd, err);
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns execAsync(cmd)
|
||||
*/
|
||||
export async function sh(cmd: string | string[]): Promise<string> {
|
||||
return Utils.execAsync(cmd).catch((err) => {
|
||||
console.error(typeof cmd === 'string' ? cmd : cmd.join(' '), err);
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
export function forMonitors(widget: (monitor: number) => Gtk.Window): Window[] {
|
||||
const n = Gdk.Display.get_default()?.get_n_monitors() || 1;
|
||||
return range(n, 0).flatMap(widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns [start...length]
|
||||
*/
|
||||
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[]): 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(', ')}`));
|
||||
Notify({
|
||||
summary: 'Dependencies not found!',
|
||||
body: `The following dependencies are missing: ${missing.join(', ')}`,
|
||||
iconName: icons.ui.warning,
|
||||
timeout: 7000,
|
||||
});
|
||||
}
|
||||
|
||||
return missing.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* run app detached
|
||||
*/
|
||||
export function launchApp(app: Application): void {
|
||||
const exe = app.executable
|
||||
.split(/\s+/)
|
||||
.filter((str) => !str.startsWith('%') && !str.startsWith('@'))
|
||||
.join(' ');
|
||||
|
||||
bash(`${exe} &`);
|
||||
app.frequency += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* to use with drag and drop
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the provided filepath is a valid image
|
||||
*/
|
||||
export const isAnImage = (imgFilePath: string): boolean => {
|
||||
try {
|
||||
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';
|
||||
command += ` "${notifPayload.summary} "`;
|
||||
if (notifPayload.body) command += ` "${notifPayload.body}" `;
|
||||
if (notifPayload.appName) command += ` -a "${notifPayload.appName}"`;
|
||||
if (notifPayload.iconName) command += ` -i "${notifPayload.iconName}"`;
|
||||
if (notifPayload.urgency) command += ` -u "${notifPayload.urgency}"`;
|
||||
if (notifPayload.timeout !== undefined) command += ` -t ${notifPayload.timeout}`;
|
||||
if (notifPayload.category) command += ` -c "${notifPayload.category}"`;
|
||||
if (notifPayload.transient) command += ` -e`;
|
||||
if (notifPayload.id !== undefined) command += ` -r ${notifPayload.id}`;
|
||||
|
||||
Utils.execAsync(command);
|
||||
};
|
||||
|
||||
export const getPosition = (pos: NotificationAnchor | OSDAnchor): ('top' | 'bottom' | 'left' | 'right')[] => {
|
||||
const positionMap: { [key: string]: ('top' | 'bottom' | 'left' | 'right')[] } = {
|
||||
top: ['top'],
|
||||
'top right': ['top', 'right'],
|
||||
'top left': ['top', 'left'],
|
||||
bottom: ['bottom'],
|
||||
'bottom right': ['bottom', 'right'],
|
||||
'bottom left': ['bottom', 'left'],
|
||||
right: ['right'],
|
||||
left: ['left'],
|
||||
};
|
||||
|
||||
return positionMap[pos] || ['top'];
|
||||
};
|
||||
export 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;
|
||||
};
|
||||
|
||||
export const capitalizeFirstLetter = (str: string): string => {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
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, (): DateTime => GLib.DateTime.new_now_local()],
|
||||
});
|
||||
|
||||
export const uptime = Variable(0, {
|
||||
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'),
|
||||
};
|
||||
Reference in new issue
Block a user