diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-03-26 13:03:20 +1100 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-03-26 13:03:20 +1100 |
| commit | 4ae165172024b9dce5db3664a16db68dc42ba400 (patch) | |
| tree | d3230716c0bb8eab6ddf7d8b17825ea569f92c69 | |
| parent | calendar: notifications for events (diff) | |
| download | caelestia-shell-4ae165172024b9dce5db3664a16db68dc42ba400.tar.gz caelestia-shell-4ae165172024b9dce5db3664a16db68dc42ba400.tar.bz2 caelestia-shell-4ae165172024b9dce5db3664a16db68dc42ba400.zip | |
sidebar: notifpane + scroll switch panes
Also placeholder for empty lists (notifs and events)
To switch panes, primary click + scroll
| -rw-r--r-- | scss/sidebar.scss | 9 | ||||
| -rw-r--r-- | src/modules/bar.tsx | 16 | ||||
| -rw-r--r-- | src/modules/sidebar/dashboard.tsx | 2 | ||||
| -rw-r--r-- | src/modules/sidebar/index.tsx | 35 | ||||
| -rw-r--r-- | src/modules/sidebar/modules/notifications.tsx | 28 | ||||
| -rw-r--r-- | src/modules/sidebar/modules/upcoming.tsx | 22 | ||||
| -rw-r--r-- | src/modules/sidebar/notifpane.tsx | 7 |
7 files changed, 94 insertions, 25 deletions
diff --git a/scss/sidebar.scss b/scss/sidebar.scss index 249f516..8f4d6d7 100644 --- a/scss/sidebar.scss +++ b/scss/sidebar.scss @@ -73,6 +73,15 @@ } } + .empty { + color: scheme.$subtext0; + font-size: lib.s(18); + + .icon { + font-size: lib.s(48); + } + } + .user { @include lib.spacing(15); diff --git a/src/modules/bar.tsx b/src/modules/bar.tsx index 85d2add..65a2727 100644 --- a/src/modules/bar.tsx +++ b/src/modules/bar.tsx @@ -1,3 +1,4 @@ +import type SideBar from "@/modules/sidebar"; import type { Monitor } from "@/services/monitors"; import Players from "@/services/players"; import Updates from "@/services/updates"; @@ -72,10 +73,19 @@ const togglePopup = (self: JSX.Element, event: Astal.ClickEvent, name: string) = } }; +const switchPane = (name: string) => { + const sidebar = App.get_window("sidebar") as SideBar | null; + if (sidebar) { + if (sidebar.visible && sidebar.shown.get() === name) sidebar.hide(); + else sidebar.show(); + sidebar.shown.set(name); + } +}; + const OSIcon = () => ( <button className="module os-icon" - onClick={(self, event) => event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "sideleft")} + onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("dashboard")} > {osIcon} </button> @@ -446,9 +456,7 @@ const PkgUpdates = () => ( const NotifCount = () => ( <button - onClick={(self, event) => - event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "notifications") - } + onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("notifpane")} setup={self => setupCustomTooltip( self, diff --git a/src/modules/sidebar/dashboard.tsx b/src/modules/sidebar/dashboard.tsx index 936502b..d1d1185 100644 --- a/src/modules/sidebar/dashboard.tsx +++ b/src/modules/sidebar/dashboard.tsx @@ -127,7 +127,7 @@ export default () => ( <Media player={p} /> ))} <box className="separator" /> - <Notifications /> + <Notifications compact /> <box className="separator" /> <Upcoming /> </box> diff --git a/src/modules/sidebar/index.tsx b/src/modules/sidebar/index.tsx index 3b62d82..a908430 100644 --- a/src/modules/sidebar/index.tsx +++ b/src/modules/sidebar/index.tsx @@ -1,7 +1,8 @@ import type { Monitor } from "@/services/monitors"; import { bind, register, Variable } from "astal"; -import { App, Astal, Gtk, Widget } from "astal/gtk3"; +import { App, Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import Dashboard from "./dashboard"; +import NotifPane from "./notifpane"; @register() export default class SideBar extends Widget.Window { @@ -18,17 +19,29 @@ export default class SideBar extends Widget.Window { // visible: false, }); + const panes = [<Dashboard />, <NotifPane />]; + this.add( - <box vertical className="sidebar"> - <stack - vexpand - transitionType={Gtk.StackTransitionType.SLIDE_UP_DOWN} - transitionDuration={200} - shown={bind(this.shown)} - > - <Dashboard /> - </stack> - </box> + <eventbox + onScroll={(_, event) => { + if (event.modifier & Gdk.ModifierType.BUTTON1_MASK) { + const index = panes.findIndex(p => p.name === this.shown.get()) + (event.delta_y < 0 ? -1 : 1); + if (index < 0 || index >= panes.length) return; + this.shown.set(panes[index].name); + } + }} + > + <box vertical className="sidebar"> + <stack + vexpand + transitionType={Gtk.StackTransitionType.SLIDE_UP_DOWN} + transitionDuration={200} + shown={bind(this.shown)} + > + {panes} + </stack> + </box> + </eventbox> ); } } diff --git a/src/modules/sidebar/modules/notifications.tsx b/src/modules/sidebar/modules/notifications.tsx index eb8f0aa..9a9f440 100644 --- a/src/modules/sidebar/modules/notifications.tsx +++ b/src/modules/sidebar/modules/notifications.tsx @@ -3,7 +3,7 @@ import { bind } from "astal"; import { Astal, Gtk } from "astal/gtk3"; import AstalNotifd from "gi://AstalNotifd"; -const List = () => ( +const List = ({ compact }: { compact?: boolean }) => ( <box vertical valign={Gtk.Align.START} @@ -13,7 +13,7 @@ const List = () => ( const map = new Map<number, Notification>(); const addNotification = (notification: AstalNotifd.Notification) => { - const notif = (<Notification notification={notification} compact />) as Notification; + const notif = (<Notification notification={notification} compact={compact} />) as Notification; notif.connect("destroy", () => map.get(notification.id) === notif && map.delete(notification.id)); map.get(notification.id)?.destroyWithAnims(); map.set(notification.id, notif); @@ -42,7 +42,16 @@ const List = () => ( /> ); -export default () => ( +const NoNotifs = () => ( + <box homogeneous name="empty"> + <box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className="empty"> + <label className="icon" label="mark_email_unread" /> + <label label="All caught up!" /> + </box> + </box> +); + +export default ({ compact }: { compact?: boolean }) => ( <box vertical className="notifications"> <box className="header-bar"> <label @@ -63,8 +72,15 @@ export default () => ( label=" Clear" /> </box> - <scrollable expand hscroll={Gtk.PolicyType.NEVER}> - <List /> - </scrollable> + <stack + transitionType={Gtk.StackTransitionType.CROSSFADE} + transitionDuration={200} + shown={bind(AstalNotifd.get_default(), "notifications").as(n => (n.length > 0 ? "list" : "empty"))} + > + <NoNotifs /> + <scrollable expand hscroll={Gtk.PolicyType.NEVER} name="list"> + <List compact={compact} /> + </scrollable> + </stack> </box> ); diff --git a/src/modules/sidebar/modules/upcoming.tsx b/src/modules/sidebar/modules/upcoming.tsx index e2389e8..76dea56 100644 --- a/src/modules/sidebar/modules/upcoming.tsx +++ b/src/modules/sidebar/modules/upcoming.tsx @@ -61,6 +61,15 @@ const List = () => ( </box> ); +const NoEvents = () => ( + <box homogeneous name="empty"> + <box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className="empty"> + <label className="icon" label="calendar_month" /> + <label label="No upcoming events" /> + </box> + </box> +); + export default () => ( <box vertical className="upcoming"> <box className="header-bar"> @@ -76,8 +85,15 @@ export default () => ( label=" Reload" /> </box> - <scrollable className="list" hscroll={Gtk.PolicyType.NEVER}> - <List /> - </scrollable> + <stack + transitionType={Gtk.StackTransitionType.CROSSFADE} + transitionDuration={200} + shown={bind(Calendar.get_default(), "numUpcoming").as(n => (n > 0 ? "list" : "empty"))} + > + <NoEvents /> + <scrollable expand hscroll={Gtk.PolicyType.NEVER} name="list"> + <List /> + </scrollable> + </stack> </box> ); diff --git a/src/modules/sidebar/notifpane.tsx b/src/modules/sidebar/notifpane.tsx new file mode 100644 index 0000000..79290e2 --- /dev/null +++ b/src/modules/sidebar/notifpane.tsx @@ -0,0 +1,7 @@ +import Notifications from "./modules/notifications"; + +export default () => ( + <box vertical className="pane notifpane" name="notifpane"> + <Notifications /> + </box> +); |