From e8a40f31c904baeaa1817cd3e418df5ce71302c1 Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:51:59 +1100 Subject: sidebar: create upcoming module Requires ical.js and curl --- src/config/defaults.ts | 4 ++ src/config/index.ts | 1 + src/config/types.ts | 2 + src/modules/sidebar/dashboard.tsx | 3 + src/modules/sidebar/modules/upcoming.tsx | 83 ++++++++++++++++++++++ src/services/calendar.ts | 116 +++++++++++++++++++++++++++++++ src/utils/widgets.ts | 8 ++- 7 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 src/modules/sidebar/modules/upcoming.tsx (limited to 'src') diff --git a/src/config/defaults.ts b/src/config/defaults.ts index d699a45..b6bee4f 100644 --- a/src/config/defaults.ts +++ b/src/config/defaults.ts @@ -143,4 +143,8 @@ export default { }, ], }, + calendar: { + webcals: [] as string[], // An array of urls to ICS files which you can curl + upcomingDays: 7, // Number of days which count as upcoming + }, }; diff --git a/src/config/index.ts b/src/config/index.ts index d09a668..3f9bf7a 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -18,5 +18,6 @@ export const { memory, storage, wallpapers, + calendar, } = config; export default config; diff --git a/src/config/types.ts b/src/config/types.ts index aa0d921..cf828b6 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -68,4 +68,6 @@ export default { "memory.interval": NUM, "storage.interval": NUM, "wallpapers.paths": OBJ_ARR({ recursive: BOOL, path: STR }), + "calendar.webcals": ARR(STR), + "calendar.upcomingDays": NUM, } as { [k: string]: string | string[] | number[] }; 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 () => ( ))} + + ); 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} ${e.event.summary}`; +}; + +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 `${e.event.summary}\n${time}\n${locIfExists}${descIfExists}󰃭 ${e.calendar}`; +}; + +const Event = (event: IEvent) => ( + setupCustomTooltip(self, getEventTooltip(event), { useMarkup: true })}> + + + + +); + +const Day = ({ events }: { events: IEvent[] }) => ( + + +); + +const List = () => ( + + {bind(Calendar.get_default(), "upcoming").as(u => + Object.values(u) + .sort((a, b) => a[0].event.startDate.compare(b[0].event.startDate)) + .map(e => ) + )} + +); + +export default () => ( + + +