Implement framework for custom modules and out of the box custom modules as well. (#213)
* Create declarative module scaffolding * Added ram module (WIP) * Updates to options, styling and more. * Added function for styling custom modules. * Added utility functions and cleaned up code * Type and fn name updates. * Update module utils to handle absent values. * Added icon color in style2 that was missing. * Linted utils.ts * Add CPU module and update RAM module to use /proc/meminfo. * Added disk storage module. * Consolidate code * Added netstat module and removed elements from systray default ignore list. * Added keyboard layout module. * Fix hook types and move module to customModules directory * Added updates modules. * Spacing updates * Added weather module. * Added power menu and power module in bar. Increased update default interval to 6 ours. * Updated styling of bar buttons, made power menu label toggleable, etc. * Consolidate code and add dynamic tooltips based on data being used. * Make default custom mogules matugen compatible * Update base theme * Fix custom module background coloring * Remove testing opacity. * Update themes to account for new modules * Update nix stuff for libgtop (Need someone to test this) * Update nix * Update fractions to multiplications * Move styling in style directory * Implement a polling framework for variables that can dynamically adjust polling intervals. * Netstat module updates when interface name is changed. * Readme update
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Weather } from "lib/types/weather";
|
||||
import { Variable } from "types/variable";
|
||||
import icons from "../../../../icons/index.js";
|
||||
import { getWeatherStatusIcon } from "globals/weather.js";
|
||||
|
||||
export const TodayIcon = (theWeather: Variable<Weather>) => {
|
||||
return Widget.Box({
|
||||
@@ -11,15 +11,7 @@ export const TodayIcon = (theWeather: Variable<Weather>) => {
|
||||
Widget.Icon({
|
||||
class_name: "calendar-menu-weather today icon",
|
||||
icon: theWeather.bind("value").as((v) => {
|
||||
let iconQuery = v.current.condition.text
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replaceAll(" ", "_");
|
||||
|
||||
if (!v.current.is_day && iconQuery === "partly_cloudy") {
|
||||
iconQuery = "partly_cloudy_night";
|
||||
}
|
||||
return icons.weather[iconQuery];
|
||||
return getWeatherStatusIcon(v);
|
||||
}),
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,53 +1,8 @@
|
||||
import options from "options";
|
||||
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 { Weather } from "lib/types/weather.js";
|
||||
import { DEFAULT_WEATHER } from "lib/types/defaults/weather.js";
|
||||
import GLib from "gi://GLib?version=2.0"
|
||||
|
||||
const { key, interval, location } = options.menus.clock.weather;
|
||||
|
||||
const theWeather = Variable<Weather>(DEFAULT_WEATHER);
|
||||
|
||||
let weatherIntervalInstance: null | number = null;
|
||||
|
||||
const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: string) => {
|
||||
if (weatherIntervalInstance !== null) {
|
||||
GLib.source_remove(weatherIntervalInstance);
|
||||
}
|
||||
|
||||
const formattedLocation = loc.replace(" ", "%20");
|
||||
|
||||
weatherIntervalInstance = Utils.interval(weatherInterval, () => {
|
||||
Utils.execAsync(
|
||||
`curl "https://api.weatherapi.com/v1/forecast.json?key=${weatherKey}&q=${formattedLocation}&days=1&aqi=no&alerts=no"`,
|
||||
)
|
||||
.then((res) => {
|
||||
try {
|
||||
if (typeof res !== "string") {
|
||||
return theWeather.value = DEFAULT_WEATHER;
|
||||
}
|
||||
|
||||
const parsedWeather = JSON.parse(res);
|
||||
|
||||
if (Object.keys(parsedWeather).includes("error")) {
|
||||
return theWeather.value = DEFAULT_WEATHER;
|
||||
}
|
||||
|
||||
return theWeather.value = parsedWeather;
|
||||
} catch (error) {
|
||||
theWeather.value = DEFAULT_WEATHER;
|
||||
console.warn(`Failed to parse weather data: ${error}`);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(`Failed to fetch weather: ${err}`);
|
||||
theWeather.value = DEFAULT_WEATHER;
|
||||
});
|
||||
})
|
||||
};
|
||||
import { globalWeatherVar } from "globals/weather.js";
|
||||
|
||||
const WeatherWidget = () => {
|
||||
return Widget.Box({
|
||||
@@ -55,16 +10,6 @@ const WeatherWidget = () => {
|
||||
child: Widget.Box({
|
||||
class_name: "weather-container-box",
|
||||
setup: (self) => {
|
||||
Utils.merge(
|
||||
[key.bind("value"), interval.bind("value"), location.bind("value")],
|
||||
(weatherKey, weatherInterval, loc) => {
|
||||
if (!weatherKey) {
|
||||
return theWeather.value = DEFAULT_WEATHER;
|
||||
}
|
||||
weatherIntervalFn(weatherInterval, loc, weatherKey);
|
||||
},
|
||||
);
|
||||
|
||||
return (self.child = Widget.Box({
|
||||
vertical: true,
|
||||
hexpand: true,
|
||||
@@ -73,15 +18,15 @@ const WeatherWidget = () => {
|
||||
class_name: "calendar-menu-weather today",
|
||||
hexpand: true,
|
||||
children: [
|
||||
TodayIcon(theWeather),
|
||||
TodayTemperature(theWeather),
|
||||
TodayStats(theWeather),
|
||||
TodayIcon(globalWeatherVar),
|
||||
TodayTemperature(globalWeatherVar),
|
||||
TodayStats(globalWeatherVar),
|
||||
],
|
||||
}),
|
||||
Widget.Separator({
|
||||
class_name: "menu-separator weather",
|
||||
}),
|
||||
Hourly(theWeather),
|
||||
Hourly(globalWeatherVar),
|
||||
],
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ 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";
|
||||
|
||||
const { unit } = options.menus.clock.weather;
|
||||
|
||||
@@ -24,10 +25,7 @@ export const TodayStats = (theWeather: Variable<Weather>) => {
|
||||
label: Utils.merge(
|
||||
[theWeather.bind("value"), unit.bind("value")],
|
||||
(wthr: Weather, unt: Unit) => {
|
||||
if (unt === "imperial") {
|
||||
return `${Math.floor(wthr.current.wind_mph)} mph`;
|
||||
}
|
||||
return `${Math.floor(wthr.current.wind_kph)} kph`;
|
||||
return getWindConditions(wthr, unt);
|
||||
},
|
||||
),
|
||||
}),
|
||||
@@ -45,7 +43,7 @@ export const TodayStats = (theWeather: Variable<Weather>) => {
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) => `${v.forecast.forecastday[0].day.daily_chance_of_rain}%`,
|
||||
(v) => getRainChance(v),
|
||||
),
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,36 +1,10 @@
|
||||
import { Weather } from "lib/types/weather";
|
||||
import { Variable } from "types/variable";
|
||||
import options from "options";
|
||||
import { getTemperature, getWeatherIcon } from "globals/weather";
|
||||
const { unit } = options.menus.clock.weather;
|
||||
|
||||
export const TodayTemperature = (theWeather: Variable<Weather>) => {
|
||||
const getIcon = (fahren: number) => {
|
||||
const icons = {
|
||||
100: "",
|
||||
75: "",
|
||||
50: "",
|
||||
25: "",
|
||||
0: "",
|
||||
};
|
||||
const colors = {
|
||||
100: "weather-color red",
|
||||
75: "weather-color orange",
|
||||
50: "weather-color lavender",
|
||||
25: "weather-color blue",
|
||||
0: "weather-color sky",
|
||||
};
|
||||
|
||||
const threshold =
|
||||
fahren < 0
|
||||
? 0
|
||||
: [100, 75, 50, 25, 0].find((threshold) => threshold <= fahren);
|
||||
|
||||
return {
|
||||
icon: icons[threshold || 50],
|
||||
color: colors[threshold || 50],
|
||||
};
|
||||
};
|
||||
|
||||
return Widget.Box({
|
||||
hpack: "center",
|
||||
vpack: "center",
|
||||
@@ -51,11 +25,7 @@ export const TodayTemperature = (theWeather: Variable<Weather>) => {
|
||||
label: Utils.merge(
|
||||
[theWeather.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`;
|
||||
}
|
||||
return getTemperature(wthr, unt);
|
||||
},
|
||||
),
|
||||
}),
|
||||
@@ -64,11 +34,11 @@ export const TodayTemperature = (theWeather: Variable<Weather>) => {
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) =>
|
||||
`calendar-menu-weather today temp label icon txt-icon ${getIcon(Math.ceil(v.current.temp_f)).color}`,
|
||||
`calendar-menu-weather today temp label icon txt-icon ${getWeatherIcon(Math.ceil(v.current.temp_f)).color}`,
|
||||
),
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as((v) => getIcon(Math.ceil(v.current.temp_f)).icon),
|
||||
.as((v) => getWeatherIcon(Math.ceil(v.current.temp_f)).icon),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -84,7 +54,7 @@ export const TodayTemperature = (theWeather: Variable<Weather>) => {
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) =>
|
||||
`calendar-menu-weather today condition label ${getIcon(Math.ceil(v.current.temp_f)).color}`,
|
||||
`calendar-menu-weather today condition label ${getWeatherIcon(Math.ceil(v.current.temp_f)).color}`,
|
||||
),
|
||||
label: theWeather.bind("value").as((v) => v.current.condition.text),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user