diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-01-27 21:55:02 +1100 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-01-27 21:55:02 +1100 |
| commit | df3b51399cbe82b083ef04230f3b340e12621afb (patch) | |
| tree | 666a6f23df7cd6f06cd1c00b72ca6312b57f45b3 /src/modules | |
| parent | popupwindow: fix offscreen popup (diff) | |
| download | caelestia-shell-df3b51399cbe82b083ef04230f3b340e12621afb.tar.gz caelestia-shell-df3b51399cbe82b083ef04230f3b340e12621afb.tar.bz2 caelestia-shell-df3b51399cbe82b083ef04230f3b340e12621afb.zip | |
sideright: make popdown window
Weather requires a weather api key from https://weatherapi.com
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/bar.tsx | 25 | ||||
| -rw-r--r-- | src/modules/popdowns/index.tsx | 2 | ||||
| -rw-r--r-- | src/modules/popdowns/sideright.tsx | 127 |
3 files changed, 139 insertions, 15 deletions
diff --git a/src/modules/bar.tsx b/src/modules/bar.tsx index c7f168e..5faee7a 100644 --- a/src/modules/bar.tsx +++ b/src/modules/bar.tsx @@ -1,4 +1,4 @@ -import { execAsync, GLib, register, Variable } from "astal"; +import { execAsync, register, Variable } from "astal"; import { bind, kebabify } from "astal/binding"; import { App, Astal, astalify, Gdk, Gtk, type ConstructProps } from "astal/gtk3"; import AstalBluetooth from "gi://AstalBluetooth"; @@ -13,7 +13,7 @@ import Players from "../services/players"; import Updates from "../services/updates"; import { getAppCategoryIcon } from "../utils/icons"; import { ellipsize } from "../utils/strings"; -import { osIcon } from "../utils/system"; +import { bindCurrentTime, osIcon } from "../utils/system"; import { setupCustomTooltip } from "../utils/widgets"; import type PopupWindow from "../widgets/popupwindow"; @@ -438,19 +438,14 @@ const NotifCount = () => ( ); const DateTime = () => ( - <box className="module date-time"> - <label className="icon" label="calendar_month" /> - <label - setup={self => { - const pollVar = Variable(null).poll(5000, () => { - self.label = - GLib.DateTime.new_now_local().format(config.dateTimeFormat) ?? new Date().toLocaleString(); - return null; - }); - self.connect("destroy", () => pollVar.drop()); - }} - /> - </box> + <button + onClick={(self, event) => event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "sideright")} + > + <box className="module date-time"> + <label className="icon" label="calendar_month" /> + <label label={bindCurrentTime(config.dateTimeFormat)} /> + </box> + </button> ); const Power = () => ( diff --git a/src/modules/popdowns/index.tsx b/src/modules/popdowns/index.tsx index 9ee9f77..c4f4664 100644 --- a/src/modules/popdowns/index.tsx +++ b/src/modules/popdowns/index.tsx @@ -2,6 +2,7 @@ import BluetoothDevices from "./bluetoothdevices"; import Media from "./media"; import Networks from "./networks"; import Notifications from "./notifications"; +import SideRight from "./sideright"; import Updates from "./updates"; export default () => { @@ -10,6 +11,7 @@ export default () => { <BluetoothDevices />; <Networks />; <Media />; + <SideRight />; return null; }; diff --git a/src/modules/popdowns/sideright.tsx b/src/modules/popdowns/sideright.tsx new file mode 100644 index 0000000..86c0547 --- /dev/null +++ b/src/modules/popdowns/sideright.tsx @@ -0,0 +1,127 @@ +import { bind } from "astal"; +import { Astal, Gtk, type Gdk } from "astal/gtk3"; +import SWeather, { type WeatherData } from "../../services/weather"; +import { ellipsize } from "../../utils/strings"; +import { bindCurrentTime } from "../../utils/system"; +import { Calendar as WCal } from "../../utils/widgets"; +import PopupWindow from "../../widgets/popupwindow"; + +const getHoursFromUpdate = (data: WeatherData, hours: number) => { + const updateTime = data.location.localtime_epoch; + const updateHourStart = updateTime - (updateTime % 3600); + + let nextHour = new Date((updateHourStart + hours * 3600) * 1000).getHours(); + if (nextHour >= 24) nextHour -= 24; + + return nextHour; +}; + +const Time = () => ( + <box className="time"> + <box hexpand halign={Gtk.Align.CENTER}> + <label label={bindCurrentTime("%I:%M:%S")} /> + <label className="ampm" label={bindCurrentTime("%p", c => (c.get_hour() < 12 ? "AM" : "PM"))} /> + </box> + </box> +); + +const Calendar = () => ( + <box className="calendar"> + <eventbox + setup={self => { + self.connect("button-press-event", (_, event: Gdk.Event) => { + if (event.get_button()[1] === Astal.MouseButton.MIDDLE) { + const now = new Date(); + const child = self.get_child() as WCal | null; + if (!child) return; + child.select_month(now.getMonth(), now.getFullYear()); + } + }); + }} + > + <WCal + hexpand + showDetails={false} + day={0} + setup={self => { + const update = () => { + const now = new Date(); + if (self.month === now.getMonth() && self.year === now.getFullYear()) self.day = now.getDate(); + else self.day = 0; + }; + self.connect("month-changed", update); + self.connect("next-month", update); + self.connect("prev-month", update); + self.connect("next-year", update); + self.connect("prev-year", update); + update(); + }} + /> + </eventbox> + </box> +); + +const Weather = () => { + const weather = SWeather.get_default(); + + return ( + <box vertical className="weather"> + <centerbox className="current"> + <label + halign={Gtk.Align.START} + valign={Gtk.Align.CENTER} + className="status-icon" + label={bind(weather, "icon")} + /> + <box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className="status"> + <box halign={Gtk.Align.CENTER} className="temperature"> + <label label={bind(weather, "temperature").as(t => `${Math.round(t)}°C`)} /> + <label + className={bind(weather, "tempColour").as(c => `temp-icon ${c}`)} + label={bind(weather, "tempIcon")} + /> + </box> + <label label={bind(weather, "condition").as(c => ellipsize(c, 16))} /> + </box> + <box vertical halign={Gtk.Align.END} valign={Gtk.Align.CENTER} className="other-data"> + <label xalign={0} label={bind(weather, "wind").as(w => ` ${Math.round(w)} kph`)} /> + <label xalign={0} label={bind(weather, "rainChance").as(r => ` ${r}%`)} /> + </box> + </centerbox> + <box className="separator" /> + <box className="forecast"> + {Array.from({ length: 4 }).map((_, i) => ( + <box vertical hexpand className="hour"> + <label + label={bind(weather, "raw").as(r => { + const hour = getHoursFromUpdate(r, i + 1); + return `${hour % 12 || 12}${hour < 12 ? "AM" : "PM"}`; + })} + /> + <label + className="icon" + label={bind(weather, "raw").as(r => + weather.getIcon(weather.forecast[getHoursFromUpdate(r, i + 1)]?.condition.text ?? "") + )} + /> + <label + label={bind(weather, "raw").as( + r => `${Math.round(weather.forecast[getHoursFromUpdate(r, i + 1)]?.temp_c) ?? "-"}°C` + )} + /> + </box> + ))} + </box> + </box> + ); +}; + +export default () => ( + <PopupWindow name="sideright"> + <box vertical className="sideright"> + <Time /> + <Calendar /> + <Weather /> + </box> + </PopupWindow> +); |