summaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-03-27 21:02:05 +1100
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-03-27 21:02:05 +1100
commit3b2130f286b9d2a15b73d55e48c532a43cf9fe08 (patch)
treeb2cfb040709a223fa3a0a4f6c6b41dedaaab6fb6 /src/modules
parentsidebar: package news module (diff)
downloadcaelestia-shell-3b2130f286b9d2a15b73d55e48c532a43cf9fe08.tar.gz
caelestia-shell-3b2130f286b9d2a15b73d55e48c532a43cf9fe08.tar.bz2
caelestia-shell-3b2130f286b9d2a15b73d55e48c532a43cf9fe08.zip
sidebar: updates module
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/sidebar/modules/news.tsx2
-rw-r--r--src/modules/sidebar/modules/updates.tsx109
-rw-r--r--src/modules/sidebar/packages.tsx1
3 files changed, 111 insertions, 1 deletions
diff --git a/src/modules/sidebar/modules/news.tsx b/src/modules/sidebar/modules/news.tsx
index f3be53e..aba37c7 100644
--- a/src/modules/sidebar/modules/news.tsx
+++ b/src/modules/sidebar/modules/news.tsx
@@ -99,7 +99,7 @@ export default () => (
>
<NoNews />
<scrollable
- expand={bind(Updates.get_default(), "news").as(n => !!n)}
+ className={bind(Updates.get_default(), "news").as(n => (n ? "expanded" : ""))}
hscroll={Gtk.PolicyType.NEVER}
name="list"
>
diff --git a/src/modules/sidebar/modules/updates.tsx b/src/modules/sidebar/modules/updates.tsx
new file mode 100644
index 0000000..3b159c6
--- /dev/null
+++ b/src/modules/sidebar/modules/updates.tsx
@@ -0,0 +1,109 @@
+import Palette from "@/services/palette";
+import Updates, { Repo as IRepo, Update as IUpdate } from "@/services/updates";
+import { MenuItem, setupCustomTooltip } from "@/utils/widgets";
+import { bind, execAsync, GLib, Variable } from "astal";
+import { Astal, Gtk } from "astal/gtk3";
+
+const constructItem = (label: string, exec: string, quiet = true) =>
+ new MenuItem({ label, onActivate: () => execAsync(exec).catch(e => !quiet && console.error(e)) });
+
+const Update = (update: IUpdate) => {
+ const menu = new Gtk.Menu();
+ menu.append(constructItem("Open info in browser", `xdg-open '${update.url}'`, false));
+ menu.append(constructItem("Open info in terminal", `uwsm app -- foot -H -- pacman -Qi ${update.name}`));
+ menu.append(new Gtk.SeparatorMenuItem({ visible: true }));
+ menu.append(constructItem("Reinstall", `uwsm app -- foot -H -- yay -S ${update.name}`));
+ menu.append(constructItem("Remove with dependencies", `uwsm app -- foot -H -- yay -Rns ${update.name}`));
+
+ return (
+ <button
+ onClick={(_, event) => event.button === Astal.MouseButton.SECONDARY && menu.popup_at_pointer(null)}
+ onDestroy={() => menu.destroy()}
+ >
+ <label
+ truncate
+ useMarkup
+ xalign={0}
+ label={bind(Palette.get_default(), "colours").as(
+ c =>
+ `${update.name} <span foreground="${c.teal}">(${update.version.old} -> ${
+ update.version.new
+ })</span>\n <span foreground="${c.subtext0}">${GLib.markup_escape_text(
+ update.description,
+ update.description.length
+ )}</span>`
+ )}
+ setup={self => setupCustomTooltip(self, `${update.name} • ${update.description}`)}
+ />
+ </button>
+ );
+};
+
+const Repo = ({ repo }: { repo: IRepo }) => {
+ const expanded = Variable(false);
+
+ return (
+ <box vertical className="repo">
+ <button className="wrapper" cursor="pointer" onClicked={() => expanded.set(!expanded.get())}>
+ <box className="header">
+ <label className="icon" label={repo.icon} />
+ <label label={`${repo.name} (${repo.updates.length})`} />
+ <box hexpand />
+ <label className="icon" label={bind(expanded).as(e => (e ? "expand_less" : "expand_more"))} />
+ </box>
+ </button>
+ <revealer
+ revealChild={bind(expanded)}
+ transitionType={Gtk.RevealerTransitionType.SLIDE_DOWN}
+ transitionDuration={200}
+ >
+ <box vertical className="body">
+ {repo.updates.map(Update)}
+ </box>
+ </revealer>
+ </box>
+ );
+};
+
+const List = () => (
+ <box vertical valign={Gtk.Align.START} className="list">
+ {bind(Updates.get_default(), "updateData").as(d => d.repos.map(r => <Repo repo={r} />))}
+ </box>
+);
+
+const NoUpdates = () => (
+ <box homogeneous name="empty">
+ <box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className="empty">
+ <label className="icon" label="deployed_code_history" />
+ <label label="All packages up to date!" />
+ </box>
+ </box>
+);
+
+export default () => (
+ <box vertical className="updates">
+ <box className="header-bar">
+ <label
+ label={bind(Updates.get_default(), "numUpdates").as(n => `${n} update${n === 1 ? "" : "s"} available`)}
+ />
+ <box hexpand />
+ <button
+ className={bind(Updates.get_default(), "loading").as(l => (l ? "enabled" : ""))}
+ sensitive={bind(Updates.get_default(), "loading").as(l => !l)}
+ cursor="pointer"
+ onClicked={() => Updates.get_default().getUpdates()}
+ label={bind(Updates.get_default(), "loading").as(l => (l ? "󰑓 Loading" : "󰑓 Reload"))}
+ />
+ </box>
+ <stack
+ transitionType={Gtk.StackTransitionType.CROSSFADE}
+ transitionDuration={200}
+ shown={bind(Updates.get_default(), "numUpdates").as(n => (n > 0 ? "list" : "empty"))}
+ >
+ <NoUpdates />
+ <scrollable expand hscroll={Gtk.PolicyType.NEVER} name="list">
+ <List />
+ </scrollable>
+ </stack>
+ </box>
+);
diff --git a/src/modules/sidebar/packages.tsx b/src/modules/sidebar/packages.tsx
index 97381b1..c073850 100644
--- a/src/modules/sidebar/packages.tsx
+++ b/src/modules/sidebar/packages.tsx
@@ -3,6 +3,7 @@ import Updates from "./modules/updates";
export default () => (
<box vertical className="pane packages" name="packages">
+ <Updates />
<box className="separator" />
<News />
</box>