diff options
Diffstat (limited to 'src/modules/sidebar')
| -rw-r--r-- | src/modules/sidebar/dashboard.tsx | 3 | ||||
| -rw-r--r-- | src/modules/sidebar/modules/upcoming.tsx | 83 |
2 files changed, 86 insertions, 0 deletions
diff --git a/src/modules/sidebar/dashboard.tsx b/src/modules/sidebar/dashboard.tsx index 86921e6..936502b 100644 --- a/src/modules/sidebar/dashboard.tsx +++ b/src/modules/sidebar/dashboard.tsx @@ -5,6 +5,7 @@ import { bind, GLib, monitorFile, Variable } from "astal"; import { Gtk } from "astal/gtk3"; import AstalMpris from "gi://AstalMpris"; import Notifications from "./modules/notifications"; +import Upcoming from "./modules/upcoming"; const lengthStr = (length: number) => `${Math.floor(length / 60)}:${Math.floor(length % 60) @@ -127,5 +128,7 @@ export default () => ( ))} <box className="separator" /> <Notifications /> + <box className="separator" /> + <Upcoming /> </box> ); diff --git a/src/modules/sidebar/modules/upcoming.tsx b/src/modules/sidebar/modules/upcoming.tsx new file mode 100644 index 0000000..e2389e8 --- /dev/null +++ b/src/modules/sidebar/modules/upcoming.tsx @@ -0,0 +1,83 @@ +import Calendar, { type IEvent } from "@/services/calendar"; +import { setupCustomTooltip } from "@/utils/widgets"; +import { bind, GLib } from "astal"; +import { Gtk } from "astal/gtk3"; + +const getDateHeader = (events: IEvent[]) => { + const date = events[0].event.startDate; + const isToday = date.toJSDate().toDateString() === new Date().toDateString(); + return ( + (isToday ? "Today • " : "") + + GLib.DateTime.new_from_unix_local(date.toUnixTime()).format("%B %-d • %A") + + ` • ${events.length} event${events.length === 1 ? "" : "s"}` + ); +}; + +const getEventHeader = (e: IEvent) => { + const start = GLib.DateTime.new_from_unix_local(e.event.startDate.toUnixTime()); + const time = `${start.format("%-I")}${start.get_minute() > 0 ? `:${start.get_minute()}` : ""}${start.format("%P")}`; + return `${time} <b>${e.event.summary}</b>`; +}; + +const getEventTooltip = (e: IEvent) => { + const start = GLib.DateTime.new_from_unix_local(e.event.startDate.toUnixTime()); + const end = GLib.DateTime.new_from_unix_local(e.event.endDate.toUnixTime()); + const sameAmPm = start.format("%P") === end.format("%P"); + const time = `${start.format(`%A, %-d %B • %-I:%M${sameAmPm ? "" : "%P"}`)} — ${end.format("%-I:%M%P")}`; + const locIfExists = e.event.location ? ` ${e.event.location}\n` : ""; + const descIfExists = e.event.description ? ` ${e.event.description}\n` : ""; + return `<b>${e.event.summary}</b>\n${time}\n${locIfExists}${descIfExists} ${e.calendar}`; +}; + +const Event = (event: IEvent) => ( + <box className="event" setup={self => setupCustomTooltip(self, getEventTooltip(event), { useMarkup: true })}> + <box className={`calendar-indicator c${Calendar.get_default().getCalendarIndex(event.calendar)}`} /> + <box vertical> + <label truncate useMarkup xalign={0} label={getEventHeader(event)} /> + {event.event.location && <label truncate xalign={0} label={event.event.location} className="sublabel" />} + {event.event.description && ( + <label truncate useMarkup xalign={0} label={event.event.description} className="sublabel" /> + )} + </box> + </box> +); + +const Day = ({ events }: { events: IEvent[] }) => ( + <box vertical className="day"> + <label className="date" xalign={0} label={getDateHeader(events)} /> + <box vertical className="events"> + {events.map(Event)} + </box> + </box> +); + +const List = () => ( + <box vertical valign={Gtk.Align.START}> + {bind(Calendar.get_default(), "upcoming").as(u => + Object.values(u) + .sort((a, b) => a[0].event.startDate.compare(b[0].event.startDate)) + .map(e => <Day events={e} />) + )} + </box> +); + +export default () => ( + <box vertical className="upcoming"> + <box className="header-bar"> + <label + label={bind(Calendar.get_default(), "numUpcoming").as(n => `${n} upcoming event${n === 1 ? "" : "s"}`)} + /> + <box hexpand /> + <button + className={bind(Calendar.get_default(), "loading").as(l => (l ? "enabled" : ""))} + sensitive={bind(Calendar.get_default(), "loading").as(l => !l)} + cursor="pointer" + onClicked={() => Calendar.get_default().updateCalendars().catch(console.error)} + label=" Reload" + /> + </box> + <scrollable className="list" hscroll={Gtk.PolicyType.NEVER}> + <List /> + </scrollable> + </box> +); |