hyprpanel
This commit is contained in:
1 parent
10080a83ee
commit
5151ac24da
322 files changed
+38276
No files matched your search
@@ -0,0 +1,24 @@
|
||||
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,
|
||||
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 };
|
||||
@@ -0,0 +1,36 @@
|
||||
import DropdownMenu from 'modules/menus/shared/dropdown/index';
|
||||
import { TimeWidget } from './time/index';
|
||||
import { CalendarWidget } from './calendar';
|
||||
import { WeatherWidget } from './weather/index';
|
||||
import options from 'options';
|
||||
import Window from 'types/widgets/window';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
|
||||
const { enabled: weatherEnabled } = options.menus.clock.weather;
|
||||
|
||||
export default (): Window<Child, Attribute> => {
|
||||
return DropdownMenu({
|
||||
name: 'calendarmenu',
|
||||
transition: options.menus.transition.bind('value'),
|
||||
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: weatherEnabled.bind('value').as((isWeatherEnabled) => {
|
||||
return [TimeWidget(), CalendarWidget(), ...(isWeatherEnabled ? [WeatherWidget()] : [])];
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
import { BoxWidget } from 'lib/types/widget';
|
||||
import options from 'options';
|
||||
|
||||
const { military, hideSeconds } = options.menus.clock.time;
|
||||
|
||||
const time = Variable('', {
|
||||
poll: [1000, 'date "+%I:%M:%S"'],
|
||||
});
|
||||
|
||||
const period = Variable('', {
|
||||
poll: [1000, 'date "+%p"'],
|
||||
});
|
||||
|
||||
const militaryTime = Variable('', {
|
||||
poll: [1000, 'date "+%H:%M:%S"'],
|
||||
});
|
||||
|
||||
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: Utils.merge(
|
||||
[military.bind('value'), hideSeconds.bind('value')],
|
||||
(is24hr: boolean, hideSeconds: boolean) => {
|
||||
if (!is24hr) {
|
||||
return [
|
||||
Widget.Box({
|
||||
hpack: 'center',
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: 'clock-content-time',
|
||||
label: hideSeconds ? time.bind().as((str) => str.slice(0, -3)) : 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: hideSeconds
|
||||
? militaryTime.bind().as((str) => str.slice(0, -3))
|
||||
: militaryTime.bind(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
];
|
||||
},
|
||||
),
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
export { TimeWidget };
|
||||
@@ -0,0 +1,43 @@
|
||||
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<Weather>, 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);
|
||||
|
||||
if (weatherAtEpoch === undefined) {
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
let iconQuery = weatherAtEpoch.condition.text.trim().toLowerCase().replaceAll(' ', '_');
|
||||
|
||||
if (!weatherAtEpoch?.is_day && iconQuery === 'partly_cloudy') {
|
||||
iconQuery = 'partly_cloudy_night';
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
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<Weather>): BoxWidget => {
|
||||
return Widget.Box({
|
||||
vertical: false,
|
||||
hexpand: true,
|
||||
hpack: 'fill',
|
||||
class_name: 'hourly-weather-container',
|
||||
children: [1, 2, 3, 4].map((hoursFromNow) => {
|
||||
return Widget.Box({
|
||||
class_name: 'hourly-weather-item',
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
children: [
|
||||
HourlyTime(theWeather, hoursFromNow),
|
||||
HourlyIcon(theWeather, hoursFromNow),
|
||||
HourlyTemp(theWeather, hoursFromNow),
|
||||
],
|
||||
});
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
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<Weather>, hoursFromNow: number): Label<Child> => {
|
||||
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, 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`;
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
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<Weather>, hoursFromNow: number): Label<Child> => {
|
||||
return Widget.Label({
|
||||
class_name: 'hourly-weather-time',
|
||||
label: theWeather.bind('value').as((w) => {
|
||||
if (!Object.keys(w).length) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
const nextEpoch = getNextEpoch(w, hoursFromNow);
|
||||
const dateAtEpoch = new Date(nextEpoch * 1000);
|
||||
let hours = dateAtEpoch.getHours();
|
||||
const ampm = hours >= 12 ? 'PM' : 'AM';
|
||||
hours = hours % 12 || 12;
|
||||
|
||||
return `${hours}${ampm}`;
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
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<Weather>): BoxWidget => {
|
||||
return Widget.Box({
|
||||
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);
|
||||
}),
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
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 = (): BoxWidget => {
|
||||
return Widget.Box({
|
||||
class_name: 'calendar-menu-item-container weather',
|
||||
child: Widget.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',
|
||||
hexpand: true,
|
||||
children: [
|
||||
TodayIcon(globalWeatherVar),
|
||||
TodayTemperature(globalWeatherVar),
|
||||
TodayStats(globalWeatherVar),
|
||||
],
|
||||
}),
|
||||
Widget.Separator({
|
||||
class_name: 'menu-separator weather',
|
||||
}),
|
||||
Hourly(globalWeatherVar),
|
||||
],
|
||||
}));
|
||||
},
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
export { WeatherWidget };
|
||||
@@ -0,0 +1,50 @@
|
||||
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<Weather>): BoxWidget => {
|
||||
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 txt-icon',
|
||||
label: '',
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: 'weather wind label',
|
||||
label: Utils.merge(
|
||||
[theWeather.bind('value'), unit.bind('value')],
|
||||
(wthr: Weather, unt: Unit) => {
|
||||
return getWindConditions(wthr, unt);
|
||||
},
|
||||
),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: 'weather precip',
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: 'weather precip icon txt-icon',
|
||||
label: '',
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: 'weather precip label',
|
||||
label: theWeather.bind('value').as((v) => getRainChance(v)),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
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<Weather>): BoxWidget => {
|
||||
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) => {
|
||||
return getTemperature(wthr, unt);
|
||||
}),
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: theWeather
|
||||
.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')
|
||||
.as((v) => getWeatherIcon(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 ${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