Finish all options sets
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.weather.json
|
||||
@@ -1,5 +1,8 @@
|
||||
const battery = await Service.import("battery");
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
const { show_label } = options.bar.battery;
|
||||
|
||||
const BatteryLabel = () => {
|
||||
const isVis = Variable(battery.available);
|
||||
@@ -37,16 +40,26 @@ const BatteryLabel = () => {
|
||||
class_name: "battery",
|
||||
visible: battery.bind("available"),
|
||||
tooltip_text: battery.bind("time_remaining").as((t) => t.toString()),
|
||||
setup: (self) => {
|
||||
self.hook(battery, () => {
|
||||
if (battery.available) {
|
||||
self.children = [
|
||||
children: Utils.merge(
|
||||
[battery.bind("available"), show_label.bind("value")],
|
||||
(batAvail, showLabel) => {
|
||||
if (batAvail && showLabel) {
|
||||
return [
|
||||
Widget.Icon({ icon: icon() }),
|
||||
Widget.Label({
|
||||
label: battery.bind("percent").as((p) => ` ${p}%`),
|
||||
}),
|
||||
];
|
||||
|
||||
} else if (batAvail && !showLabel) {
|
||||
return [Widget.Icon({ icon: icon() })];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
),
|
||||
setup: (self) => {
|
||||
self.hook(battery, () => {
|
||||
if (battery.available) {
|
||||
self.tooltip_text = generateTooltip(
|
||||
battery.time_remaining,
|
||||
battery.charging,
|
||||
|
||||
@@ -7,7 +7,7 @@ const activeDevices = () => {
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "menu-label-container volume",
|
||||
class_name: "menu-label-container volume selected",
|
||||
hpack: "fill",
|
||||
child: Widget.Label({
|
||||
class_name: "menu-label audio volume",
|
||||
|
||||
@@ -8,10 +8,10 @@ const Devices = () => {
|
||||
vertical: true,
|
||||
children: [
|
||||
label(bluetooth),
|
||||
Widget.Scrollable({
|
||||
Widget.Box({
|
||||
class_name: "menu-items-section",
|
||||
hscroll: 'never',
|
||||
vscroll: 'always',
|
||||
// hscroll: 'never',
|
||||
// vscroll: 'always',
|
||||
child: Widget.Box({
|
||||
class_name: "menu-content",
|
||||
vertical: true,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import options from "options";
|
||||
|
||||
const { military } = options.menus.clock.time;
|
||||
|
||||
const time = Variable("", {
|
||||
poll: [1000, 'date "+%I:%M:%S"'],
|
||||
});
|
||||
@@ -6,6 +10,10 @@ const period = Variable("", {
|
||||
poll: [1000, 'date "+%p"'],
|
||||
});
|
||||
|
||||
const militaryTime = Variable("", {
|
||||
poll: [1000, 'date "+%H:%M:%S"'],
|
||||
});
|
||||
|
||||
const TimeWidget = () => {
|
||||
return Widget.Box({
|
||||
class_name: "calendar-menu-item-container clock",
|
||||
@@ -17,7 +25,9 @@ const TimeWidget = () => {
|
||||
vpack: "center",
|
||||
hpack: "center",
|
||||
class_name: "clock-content-items",
|
||||
children: [
|
||||
children: military.bind("value").as((is24hr) => {
|
||||
if (!is24hr) {
|
||||
return [
|
||||
Widget.Box({
|
||||
hpack: "center",
|
||||
children: [
|
||||
@@ -37,8 +47,22 @@ const TimeWidget = () => {
|
||||
}),
|
||||
],
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
Widget.Box({
|
||||
hpack: "center",
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "clock-content-time",
|
||||
label: militaryTime.bind(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
];
|
||||
}),
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
28
modules/menus/calendar/weather/hourly/icon/index.js
Normal file
28
modules/menus/calendar/weather/hourly/icon/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import icons from "../../../../../icons/index.js";
|
||||
|
||||
export const HourlyIcon = (theWeather, getNextEpoch) => {
|
||||
return Widget.Icon({
|
||||
class_name: "hourly-weather-icon",
|
||||
icon: theWeather.bind("value").as((w) => {
|
||||
if (!Object.keys(w).length) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const nextEpoch = getNextEpoch(w);
|
||||
const weatherAtEpoch = w.forecast.forecastday[0].hour.find(
|
||||
(h) => h.time_epoch === nextEpoch,
|
||||
);
|
||||
|
||||
let iconQuery = weatherAtEpoch?.condition.text
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replaceAll(" ", "_");
|
||||
|
||||
if (!weatherAtEpoch?.isDay && iconQuery === "partly_cloudy") {
|
||||
iconQuery = "partly_cloudy_night";
|
||||
}
|
||||
|
||||
return icons.weather[iconQuery];
|
||||
}),
|
||||
});
|
||||
};
|
||||
44
modules/menus/calendar/weather/hourly/index.js
Normal file
44
modules/menus/calendar/weather/hourly/index.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import { HourlyIcon } from "./icon/index.js";
|
||||
import { HourlyTemp } from "./temperature/index.js";
|
||||
import { HourlyTime } from "./time/index.js";
|
||||
|
||||
export const Hourly = (theWeather) => {
|
||||
return Widget.Box({
|
||||
vertical: false,
|
||||
hexpand: true,
|
||||
hpack: "fill",
|
||||
class_name: "hourly-weather-container",
|
||||
children: [1, 2, 3, 4].map((hoursFromNow) => {
|
||||
const getNextEpoch = (wthr) => {
|
||||
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",
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
children: [
|
||||
HourlyTime(theWeather, getNextEpoch),
|
||||
HourlyIcon(theWeather, getNextEpoch),
|
||||
HourlyTemp(theWeather, getNextEpoch),
|
||||
],
|
||||
});
|
||||
}),
|
||||
});
|
||||
};
|
||||
27
modules/menus/calendar/weather/hourly/temperature/index.js
Normal file
27
modules/menus/calendar/weather/hourly/temperature/index.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import options from "options";
|
||||
|
||||
const { unit } = options.menus.clock.weather;
|
||||
|
||||
export const HourlyTemp = (theWeather, getNextEpoch) => {
|
||||
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 "-";
|
||||
}
|
||||
|
||||
const nextEpoch = getNextEpoch(wthr);
|
||||
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`;
|
||||
},
|
||||
),
|
||||
});
|
||||
};
|
||||
18
modules/menus/calendar/weather/hourly/time/index.js
Normal file
18
modules/menus/calendar/weather/hourly/time/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
export const HourlyTime = (theWeather, getNextEpoch) => {
|
||||
return Widget.Label({
|
||||
class_name: "hourly-weather-time",
|
||||
label: theWeather.bind("value").as((w) => {
|
||||
if (!Object.keys(w).length) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const nextEpoch = getNextEpoch(w);
|
||||
const dateAtEpoch = new Date(nextEpoch * 1000);
|
||||
let hours = dateAtEpoch.getHours();
|
||||
const ampm = hours >= 12 ? "PM" : "AM";
|
||||
hours = hours % 12 || 12;
|
||||
|
||||
return `${hours}${ampm}`;
|
||||
}),
|
||||
});
|
||||
};
|
||||
25
modules/menus/calendar/weather/icon/index.js
Normal file
25
modules/menus/calendar/weather/icon/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import icons from "../../../../icons/index.js";
|
||||
|
||||
export const TodayIcon = (theWeather) => {
|
||||
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) => {
|
||||
let iconQuery = v.current.condition.text
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replaceAll(" ", "_");
|
||||
|
||||
if (!v.current.isDay && iconQuery === "partly_cloudy") {
|
||||
iconQuery = "partly_cloudy_night";
|
||||
}
|
||||
return icons.weather[iconQuery];
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,10 @@
|
||||
import icons from "../../../icons/index.js";
|
||||
import { keyRing } from "../../../../../../Documents/Keys/keyList.js";
|
||||
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";
|
||||
|
||||
const { key, interval } = options.menus.clock.weather;
|
||||
|
||||
const defaultWeather = {
|
||||
location: {
|
||||
@@ -34,42 +39,18 @@ const defaultWeather = {
|
||||
|
||||
const theWeather = Variable(defaultWeather);
|
||||
|
||||
const getIcon = (fahren) => {
|
||||
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],
|
||||
color: colors[threshold],
|
||||
};
|
||||
};
|
||||
|
||||
const WeatherWidget = () => {
|
||||
return Widget.Box({
|
||||
class_name: "calendar-menu-item-container weather",
|
||||
child: Widget.Box({
|
||||
class_name: "weather-container-box",
|
||||
setup: (self) => {
|
||||
Utils.interval(60 * 1000, () => {
|
||||
Utils.merge(
|
||||
[key.bind("value"), interval.bind("value")],
|
||||
(weatherKey, weatherInterval) => {
|
||||
Utils.interval(weatherInterval, () => {
|
||||
Utils.execAsync(
|
||||
`curl "https://api.weatherapi.com/v1/forecast.json?key=${keyRing.weatherapi}&q=93722&days=1&aqi=no&alerts=no"`,
|
||||
`curl "https://api.weatherapi.com/v1/forecast.json?key=${weatherKey}&q=93722&days=1&aqi=no&alerts=no"`,
|
||||
)
|
||||
.then((res) => {
|
||||
if (typeof res === "string") {
|
||||
@@ -81,6 +62,8 @@ const WeatherWidget = () => {
|
||||
theWeather.value = defaultWeather;
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return (self.child = Widget.Box({
|
||||
vertical: true,
|
||||
@@ -90,226 +73,15 @@ const WeatherWidget = () => {
|
||||
class_name: "calendar-menu-weather today",
|
||||
hexpand: true,
|
||||
children: [
|
||||
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) => {
|
||||
let iconQuery = v.current.condition.text
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replaceAll(" ", "_")
|
||||
|
||||
if (!v.current.isDay && iconQuery === "partly_cloudy") {
|
||||
iconQuery = "partly_cloudy_night";
|
||||
}
|
||||
return icons.weather[iconQuery];
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
hpack: "center",
|
||||
vpack: "center",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vpack: "center",
|
||||
class_name: "calendar-menu-weather today temp container",
|
||||
vertical: false,
|
||||
children: [
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
hpack: "center",
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name:
|
||||
"calendar-menu-weather today temp label",
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as((v) => `${Math.ceil(v.current.temp_f)}° F`),
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: theWeather
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) =>
|
||||
`calendar-menu-weather today temp label icon ${getIcon(Math.ceil(v.current.temp_f)).color}`,
|
||||
),
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) =>
|
||||
getIcon(Math.ceil(v.current.temp_f)).icon,
|
||||
),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
hpack: "center",
|
||||
child: Widget.Label({
|
||||
max_width_chars: 17,
|
||||
truncate: "end",
|
||||
lines: 2,
|
||||
class_name: theWeather
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) =>
|
||||
`calendar-menu-weather today condition label ${getIcon(Math.ceil(v.current.temp_f)).color}`,
|
||||
),
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as((v) => v.current.condition.text),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "calendar-menu-weather today stats container",
|
||||
hpack: "end",
|
||||
vpack: "center",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "weather wind",
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "weather wind icon",
|
||||
label: "",
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "weather wind label",
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as((v) => `${Math.floor(v.current.wind_mph)} mph`),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "weather precip",
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "weather precip icon",
|
||||
label: "",
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "weather precip label",
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) =>
|
||||
`${v.forecast.forecastday[0].day.daily_chance_of_rain}%`,
|
||||
),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
TodayIcon(theWeather),
|
||||
TodayTemperature(theWeather),
|
||||
TodayStats(theWeather),
|
||||
],
|
||||
}),
|
||||
Widget.Separator({
|
||||
class_name: "menu-separator weather",
|
||||
}),
|
||||
Widget.Box({
|
||||
vertical: false,
|
||||
hexpand: true,
|
||||
hpack: "fill",
|
||||
class_name: "hourly-weather-container",
|
||||
children: [1, 2, 3, 4].map((hoursFromNow) => {
|
||||
const getNextEpoch = (wthr) => {
|
||||
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",
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "hourly-weather-time",
|
||||
label: theWeather.bind("value").as((w) => {
|
||||
if (!Object.keys(w).length) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const nextEpoch = getNextEpoch(w);
|
||||
const dateAtEpoch = new Date(nextEpoch * 1000);
|
||||
let hours = dateAtEpoch.getHours();
|
||||
const ampm = hours >= 12 ? "PM" : "AM";
|
||||
hours = hours % 12 || 12;
|
||||
|
||||
return `${hours}${ampm}`;
|
||||
}),
|
||||
}),
|
||||
Widget.Icon({
|
||||
class_name: "hourly-weather-icon",
|
||||
icon: theWeather.bind("value").as((w) => {
|
||||
if (!Object.keys(w).length) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const nextEpoch = getNextEpoch(w);
|
||||
const weatherAtEpoch =
|
||||
w.forecast.forecastday[0].hour.find(
|
||||
(h) => h.time_epoch === nextEpoch,
|
||||
);
|
||||
|
||||
let iconQuery = weatherAtEpoch?.condition.text
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replaceAll(" ", "_")
|
||||
|
||||
if (!weatherAtEpoch?.isDay && iconQuery === "partly_cloudy") {
|
||||
iconQuery = "partly_cloudy_night";
|
||||
}
|
||||
|
||||
return icons.weather[iconQuery];
|
||||
}),
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "hourly-weather-temp",
|
||||
label: theWeather.bind("value").as((w) => {
|
||||
if (!Object.keys(w).length) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const nextEpoch = getNextEpoch(w);
|
||||
const weatherAtEpoch =
|
||||
w.forecast.forecastday[0].hour.find(
|
||||
(h) => h.time_epoch === nextEpoch,
|
||||
);
|
||||
|
||||
return `${weatherAtEpoch ? Math.ceil(weatherAtEpoch.temp_f) : "-"}° F`;
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
}),
|
||||
}),
|
||||
Hourly(theWeather),
|
||||
],
|
||||
}));
|
||||
},
|
||||
|
||||
52
modules/menus/calendar/weather/stats/index.js
Normal file
52
modules/menus/calendar/weather/stats/index.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import options from "options";
|
||||
|
||||
const { unit } = options.menus.clock.weather;
|
||||
|
||||
export const TodayStats = (theWeather) => {
|
||||
return Widget.Box({
|
||||
class_name: "calendar-menu-weather today stats container",
|
||||
hpack: "end",
|
||||
vpack: "center",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "weather wind",
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "weather wind icon",
|
||||
label: "",
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "weather wind label",
|
||||
label: Utils.merge(
|
||||
[theWeather.bind("value"), unit.bind("value")],
|
||||
(wthr, unt) => {
|
||||
if (unt === "imperial") {
|
||||
return `${Math.floor(wthr.current.wind_mph)} mph`;
|
||||
}
|
||||
return `${Math.floor(wthr.current.wind_kph)} kph`;
|
||||
},
|
||||
),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "weather precip",
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "weather precip icon",
|
||||
label: "",
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "weather precip label",
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) => `${v.forecast.forecastday[0].day.daily_chance_of_rain}%`,
|
||||
),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
};
|
||||
92
modules/menus/calendar/weather/temperature/index.js
Normal file
92
modules/menus/calendar/weather/temperature/index.js
Normal file
@@ -0,0 +1,92 @@
|
||||
import options from "options";
|
||||
const { unit } = options.menus.clock.weather;
|
||||
|
||||
export const TodayTemperature = (theWeather) => {
|
||||
const getIcon = (fahren) => {
|
||||
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],
|
||||
color: colors[threshold],
|
||||
};
|
||||
};
|
||||
|
||||
return Widget.Box({
|
||||
hpack: "center",
|
||||
vpack: "center",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vpack: "center",
|
||||
class_name: "calendar-menu-weather today temp container",
|
||||
vertical: false,
|
||||
children: [
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
hpack: "center",
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "calendar-menu-weather today temp label",
|
||||
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`;
|
||||
}
|
||||
},
|
||||
),
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: theWeather
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) =>
|
||||
`calendar-menu-weather today temp label icon ${getIcon(Math.ceil(v.current.temp_f)).color}`,
|
||||
),
|
||||
label: theWeather
|
||||
.bind("value")
|
||||
.as((v) => getIcon(Math.ceil(v.current.temp_f)).icon),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
hpack: "center",
|
||||
child: Widget.Label({
|
||||
max_width_chars: 17,
|
||||
truncate: "end",
|
||||
lines: 2,
|
||||
class_name: theWeather
|
||||
.bind("value")
|
||||
.as(
|
||||
(v) =>
|
||||
`calendar-menu-weather today condition label ${getIcon(Math.ceil(v.current.temp_f)).color}`,
|
||||
),
|
||||
label: theWeather.bind("value").as((v) => v.current.condition.text),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
};
|
||||
@@ -1,8 +1,9 @@
|
||||
import GLib from "gi://GLib";
|
||||
import options from "options";
|
||||
|
||||
const { left, right } = options.menus.dashboard.directories;
|
||||
|
||||
const Directories = () => {
|
||||
const homeDir = GLib.get_home_dir();
|
||||
|
||||
return Widget.Box({
|
||||
class_name: "dashboard-card directories-container",
|
||||
vpack: "fill",
|
||||
@@ -18,45 +19,51 @@ const Directories = () => {
|
||||
hpack: "start",
|
||||
expand: true,
|
||||
class_name: "directory-link left top",
|
||||
on_primary_click: () => {
|
||||
on_primary_click: left.directory1.command
|
||||
.bind("value")
|
||||
.as((cmd) => {
|
||||
return () => {
|
||||
App.closeWindow("dashboardmenu");
|
||||
Utils.execAsync(`dolphin ${homeDir}/Downloads`).catch(
|
||||
(err) => `Failed to open Dolphin: ${err}`,
|
||||
);
|
||||
},
|
||||
Utils.execAsync(cmd);
|
||||
};
|
||||
}),
|
||||
child: Widget.Label({
|
||||
hpack: "start",
|
||||
label: " Downloads",
|
||||
label: left.directory1.label.bind("value"),
|
||||
}),
|
||||
}),
|
||||
Widget.Button({
|
||||
expand: true,
|
||||
hpack: "start",
|
||||
class_name: "directory-link left middle",
|
||||
on_primary_click: () => {
|
||||
on_primary_click: left.directory2.command
|
||||
.bind("value")
|
||||
.as((cmd) => {
|
||||
return () => {
|
||||
App.closeWindow("dashboardmenu");
|
||||
Utils.execAsync(`dolphin ${homeDir}/Videos`).catch(
|
||||
(err) => `Failed to open Dolphin: ${err}`,
|
||||
);
|
||||
},
|
||||
Utils.execAsync(cmd);
|
||||
};
|
||||
}),
|
||||
child: Widget.Label({
|
||||
hpack: "start",
|
||||
label: " Videos",
|
||||
label: left.directory2.label.bind("value"),
|
||||
}),
|
||||
}),
|
||||
Widget.Button({
|
||||
expand: true,
|
||||
hpack: "start",
|
||||
class_name: "directory-link left bottom",
|
||||
on_primary_click: () => {
|
||||
on_primary_click: left.directory3.command
|
||||
.bind("value")
|
||||
.as((cmd) => {
|
||||
return () => {
|
||||
App.closeWindow("dashboardmenu");
|
||||
Utils.execAsync(`dolphin ${homeDir}/Projects`).catch(
|
||||
(err) => `Failed to open Dolphin: ${err}`,
|
||||
);
|
||||
},
|
||||
Utils.execAsync(cmd);
|
||||
};
|
||||
}),
|
||||
child: Widget.Label({
|
||||
hpack: "start",
|
||||
label: " Projects",
|
||||
label: left.directory3.label.bind("value"),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
@@ -70,45 +77,51 @@ const Directories = () => {
|
||||
hpack: "start",
|
||||
expand: true,
|
||||
class_name: "directory-link right top",
|
||||
on_primary_click: () => {
|
||||
on_primary_click: right.directory1.command
|
||||
.bind("value")
|
||||
.as((cmd) => {
|
||||
return () => {
|
||||
App.closeWindow("dashboardmenu");
|
||||
Utils.execAsync(`dolphin ${homeDir}/Documents`).catch(
|
||||
(err) => `Failed to open Dolphin: ${err}`,
|
||||
);
|
||||
},
|
||||
Utils.execAsync(cmd);
|
||||
};
|
||||
}),
|
||||
child: Widget.Label({
|
||||
hpack: "start",
|
||||
label: " Documents",
|
||||
label: right.directory1.label.bind("value"),
|
||||
}),
|
||||
}),
|
||||
Widget.Button({
|
||||
expand: true,
|
||||
hpack: "start",
|
||||
class_name: "directory-link right middle",
|
||||
on_primary_click: () => {
|
||||
on_primary_click: right.directory2.command
|
||||
.bind("value")
|
||||
.as((cmd) => {
|
||||
return () => {
|
||||
App.closeWindow("dashboardmenu");
|
||||
Utils.execAsync(`dolphin ${homeDir}/Pictures`).catch(
|
||||
(err) => `Failed to open Dolphin: ${err}`,
|
||||
);
|
||||
},
|
||||
Utils.execAsync(cmd);
|
||||
};
|
||||
}),
|
||||
child: Widget.Label({
|
||||
hpack: "start",
|
||||
label: " Pictures",
|
||||
label: right.directory2.label.bind("value"),
|
||||
}),
|
||||
}),
|
||||
Widget.Button({
|
||||
expand: true,
|
||||
hpack: "start",
|
||||
class_name: "directory-link right bottom",
|
||||
on_primary_click: () => {
|
||||
on_primary_click: right.directory3.command
|
||||
.bind("value")
|
||||
.as((cmd) => {
|
||||
return () => {
|
||||
App.closeWindow("dashboardmenu");
|
||||
Utils.execAsync(`dolphin ${homeDir}/`).catch(
|
||||
(err) => `Failed to open Dolphin: ${err}`,
|
||||
);
|
||||
},
|
||||
Utils.execAsync(cmd);
|
||||
};
|
||||
}),
|
||||
child: Widget.Label({
|
||||
hpack: "start",
|
||||
label: " Home",
|
||||
label: right.directory3.label.bind("value"),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const notifs = await Service.import("notifications");
|
||||
import options from "options";
|
||||
import { notifHasImg } from "../menus/notifications/utils.js";
|
||||
import { Image } from "./image/index.js";
|
||||
import { Action } from "./actions/index.js";
|
||||
@@ -6,6 +7,8 @@ import { Header } from "./header/index.js";
|
||||
import { Body } from "./body/index.js";
|
||||
import { CloseButton } from "./close/index.js";
|
||||
|
||||
const { position } = options.notifications;
|
||||
|
||||
export default () => {
|
||||
notifs.popupTimeout = 7000;
|
||||
|
||||
@@ -14,7 +17,7 @@ export default () => {
|
||||
class_name: "notifications-window",
|
||||
monitor: 2,
|
||||
layer: "top",
|
||||
anchor: ["top", "right"],
|
||||
anchor: position.bind("value"),
|
||||
exclusivity: "ignore",
|
||||
child: Widget.Box({
|
||||
class_name: "notification-card-container",
|
||||
|
||||
54
options.ts
54
options.ts
@@ -41,8 +41,7 @@ const options = mkOptions(OPTIONS, {
|
||||
notification: {
|
||||
background: opt(colors.mantle),
|
||||
actions: {
|
||||
background: opt(colors.surface0),
|
||||
hover: opt(colors.surface1),
|
||||
background: opt(colors.lavender),
|
||||
text: opt(colors.mantle),
|
||||
},
|
||||
label: opt(colors.lavender),
|
||||
@@ -138,10 +137,10 @@ const options = mkOptions(OPTIONS, {
|
||||
monochrome: opt(true),
|
||||
background: opt(colors.crust),
|
||||
cards: opt(colors.base),
|
||||
card_radius: opt("0.4em"),
|
||||
border: {
|
||||
size: opt("0.13 em"),
|
||||
radius: opt("0.7em"),
|
||||
card_radius: opt("0.4em"),
|
||||
color: opt(colors.surface0)
|
||||
},
|
||||
text: opt(colors.text),
|
||||
@@ -640,72 +639,55 @@ const options = mkOptions(OPTIONS, {
|
||||
shortcut3: {
|
||||
icon: opt(""),
|
||||
tooltip: opt("Screenshot"),
|
||||
command: opt("./services/snapshot.sh")
|
||||
command: opt("bash -c \"$HOME/.config/ags/services/snapshot.sh\"")
|
||||
},
|
||||
}
|
||||
},
|
||||
directories: {
|
||||
left: {
|
||||
directory1: {
|
||||
label: opt(""),
|
||||
command: opt("")
|
||||
label: opt(" Downloads"),
|
||||
command: opt("bash -c \"dolphin $HOME/Downloads/\"")
|
||||
},
|
||||
directory2: {
|
||||
label: opt(""),
|
||||
command: opt("")
|
||||
label: opt(" Videos"),
|
||||
command: opt("bash -c \"dolphin $HOME/Videos/\"")
|
||||
},
|
||||
directory3: {
|
||||
label: opt(""),
|
||||
command: opt("")
|
||||
label: opt(" Projects"),
|
||||
command: opt("bash -c \"dolphin $HOME/Projects/\"")
|
||||
},
|
||||
},
|
||||
right: {
|
||||
directory1: {
|
||||
label: opt(""),
|
||||
command: opt("")
|
||||
label: opt(" Documents"),
|
||||
command: opt("bash -c \"dolphin $HOME/Documents/\"")
|
||||
},
|
||||
directory2: {
|
||||
label: opt(""),
|
||||
command: opt("")
|
||||
label: opt(" Pictures"),
|
||||
command: opt("bash -c \"dolphin $HOME/Pictures/\"")
|
||||
},
|
||||
directory3: {
|
||||
label: opt(""),
|
||||
command: opt("")
|
||||
label: opt(" Home"),
|
||||
command: opt("bash -c \"dolphin $HOME/\"")
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
network: {
|
||||
status: opt(true),
|
||||
},
|
||||
bluetooth: {
|
||||
status: opt(true),
|
||||
},
|
||||
battery: {
|
||||
percentage: opt(true)
|
||||
},
|
||||
clock: {
|
||||
time: {
|
||||
military: opt(false),
|
||||
seconds: opt(true)
|
||||
},
|
||||
weather: {
|
||||
hourly: opt(true),
|
||||
interval: opt(60_000),
|
||||
unit: opt<"metric" | "imperial" | "standard">("metric"),
|
||||
unit: opt<"metric" | "imperial">("metric"),
|
||||
key: opt<string>(
|
||||
JSON.parse(Utils.readFile(`${App.configDir}/.weather`) || "{}")?.key || "",
|
||||
JSON.parse(Utils.readFile(`${App.configDir}/.weather.json`) || "{}")?.weather_api_key || "",
|
||||
),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
overview: {
|
||||
scale: opt(9),
|
||||
workspaces: opt(7),
|
||||
monochromeIcon: opt(true),
|
||||
},
|
||||
|
||||
osd: {
|
||||
progress: {
|
||||
vertical: opt(true),
|
||||
@@ -724,10 +706,8 @@ const options = mkOptions(OPTIONS, {
|
||||
|
||||
notifications: {
|
||||
position: opt<Array<"top" | "bottom" | "left" | "right">>(["top", "right"]),
|
||||
blacklist: opt(["Spotify"]),
|
||||
},
|
||||
})
|
||||
|
||||
globalThis["options"] = options
|
||||
export default options
|
||||
|
||||
|
||||
@@ -132,6 +132,22 @@
|
||||
|
||||
.menu-label-container.input {
|
||||
border-radius: 0em;
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-volume-card-color);
|
||||
}
|
||||
.menu-label-container.playback {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-volume-card-color);
|
||||
}
|
||||
.menu-items-section.input {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-volume-card-color);
|
||||
}
|
||||
.menu-items-section.playback {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-volume-card-color);
|
||||
}
|
||||
.menu-label-container.selected {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-volume-card-color);
|
||||
}
|
||||
.menu-items-section.selected {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-volume-card-color);
|
||||
}
|
||||
|
||||
.menu-items-section.playback {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
}
|
||||
|
||||
.menu-label-container {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-bluetooth-card-color);
|
||||
.menu-label {
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-bluetooth-label-color);
|
||||
}
|
||||
@@ -24,6 +25,7 @@
|
||||
|
||||
|
||||
.menu-items-section {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-bluetooth-card-color);
|
||||
min-height: 20em;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
@@ -31,16 +31,16 @@
|
||||
color: if($bar-menus-monochrome, $bar-menus-text, $bar-menus-menu-clock-calendar-days);
|
||||
|
||||
&:selected {
|
||||
box-shadow: inset 0 -0.5em 0 0 if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-calendar-currentday),
|
||||
box-shadow: inset 0 -0.5em 0 0 if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-calendar-currentday),
|
||||
inset -0.4em -0.3em 0 0 if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-clock-card-color),
|
||||
inset 0.4em 0 0 0.01em if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-clock-card-color);
|
||||
color: if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-calendar-currentday);
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-calendar-currentday);
|
||||
border-radius: 0em;
|
||||
}
|
||||
|
||||
&.header {
|
||||
background-color: transparent;
|
||||
color: if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-calendar-yearmonth);
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-calendar-yearmonth);
|
||||
}
|
||||
&.button {
|
||||
color: $text;
|
||||
@@ -66,13 +66,13 @@
|
||||
|
||||
.clock-content-time {
|
||||
font-size: 4em;
|
||||
color: if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-time-time);
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-time-time);
|
||||
}
|
||||
.clock-content-period {
|
||||
font-size: 1.75em;
|
||||
margin-bottom: 1.35em;
|
||||
margin-right: -0.875em;
|
||||
color: if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-time-timeperiod);
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-time-timeperiod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
}
|
||||
|
||||
.calendar-menu-weather.today.condition.label {
|
||||
color: if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-weather-status);
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-weather-status);
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
@@ -133,7 +133,7 @@
|
||||
|
||||
.calendar-menu-weather.today.stats.container {
|
||||
margin-bottom: 0.75em;
|
||||
color: if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-weather-stats);
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-weather-stats);
|
||||
|
||||
.weather.label {
|
||||
margin-left: 0.35em;
|
||||
@@ -145,7 +145,7 @@
|
||||
}
|
||||
|
||||
.hourly-weather-time {
|
||||
color: if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-weather-hourly-time);
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-weather-hourly-time);
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
@@ -155,5 +155,5 @@
|
||||
}
|
||||
|
||||
.hourly-weather-temp {
|
||||
color: if($bar-menus-monochrome, $bar-menus-icons-active, $bar-menus-menu-clock-weather-hourly-temperature);
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-clock-weather-hourly-temperature);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
color: if($bar-menus-monochrome, $bar-menus-label, $bar-menus-menu-battery-label-color);
|
||||
}
|
||||
|
||||
.menu-label-container {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-battery-card-color);
|
||||
}
|
||||
|
||||
|
||||
.menu-items-section {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-battery-card-color);
|
||||
}
|
||||
|
||||
.power-profile-item {
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
|
||||
@@ -94,8 +94,8 @@ tooltip label {
|
||||
|
||||
.menu-items {
|
||||
background: $crust;
|
||||
border: .13em solid $surface0;
|
||||
border-radius: .7rem;
|
||||
border: $bar-menus-border-size solid $bar-menus-border-color;
|
||||
border-radius: $bar-menus-border-radius;
|
||||
min-width: 18em;
|
||||
color: $text;
|
||||
}
|
||||
@@ -117,7 +117,7 @@ tooltip label {
|
||||
|
||||
.menu-label-container {
|
||||
background: $base;
|
||||
border-radius: 0.4em;
|
||||
border-radius: $bar-menus-card_radius;
|
||||
border-bottom-left-radius: 0em;
|
||||
border-bottom-right-radius: 0em;
|
||||
margin: 0em 1em ;
|
||||
@@ -138,7 +138,7 @@ tooltip label {
|
||||
|
||||
.menu-items-section {
|
||||
background: $base;
|
||||
border-radius: 0.4em;
|
||||
border-radius: $bar-menus-card_radius;
|
||||
border-top-left-radius: 0em;
|
||||
border-top-right-radius: 0em;
|
||||
padding: 0.9em;
|
||||
|
||||
@@ -118,4 +118,12 @@
|
||||
color: if($bar-menus-monochrome, $bar-menus-text, $bar-menus-menu-network-text);
|
||||
opacity: 0.5;
|
||||
}
|
||||
.menu-label-container {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-network-card-color);
|
||||
}
|
||||
|
||||
|
||||
.menu-items-section {
|
||||
background: if($bar-menus-monochrome, $bar-menus-cards, $bar-menus-menu-network-card-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,11 @@
|
||||
.notification-card {
|
||||
color: $notification-text;
|
||||
background: $notification-background;
|
||||
margin-right: 0.45em;
|
||||
margin: 0.45em;
|
||||
border: 0.15em solid transparentize($notification-border, 0.5);
|
||||
min-width: 26em;
|
||||
min-height: 6rem;
|
||||
border-radius: 0.6em;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: 0.85em;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-card-container {
|
||||
@@ -77,7 +73,7 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $notification-actions-hover;
|
||||
background: transparentize($notification-actions-background, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@ $font-size: 1.2rem;
|
||||
$font-name: Ubuntu Nerd Font;
|
||||
$font-weight: 600;
|
||||
$notification-background: #181825;
|
||||
$notification-actions-background: #313244;
|
||||
$notification-actions-hover: #45475a;
|
||||
$notification-actions-background: #b4befe;
|
||||
$notification-actions-text: #181825;
|
||||
$notification-label: #b4befe;
|
||||
$notification-border: #313244;
|
||||
@@ -64,12 +63,12 @@ $bar-buttons-notifications-background: #242438;
|
||||
$bar-buttons-notifications-hover: #45475a;
|
||||
$bar-buttons-notifications-icon: #b4befe;
|
||||
$bar-buttons-notifications-total: #b4befe;
|
||||
$bar-menus-monochrome: true;
|
||||
$bar-menus-monochrome: false;
|
||||
$bar-menus-background: #11111b;
|
||||
$bar-menus-cards: #1e1e2e;
|
||||
$bar-menus-card_radius: 0.4em;
|
||||
$bar-menus-border-size: 0.13em;
|
||||
$bar-menus-border-radius: 0.7em;
|
||||
$bar-menus-border-card_radius: 0.4em;
|
||||
$bar-menus-border-radius: 0.4em;
|
||||
$bar-menus-border-color: #313244;
|
||||
$bar-menus-text: #cdd6f4;
|
||||
$bar-menus-dimtext: #585b70;
|
||||
|
||||
Reference in New Issue
Block a user