summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/modules/sidebar/index.tsx3
-rw-r--r--src/modules/sidebar/modules/news.tsx110
-rw-r--r--src/modules/sidebar/modules/upcoming.tsx2
-rw-r--r--src/modules/sidebar/packages.tsx9
4 files changed, 122 insertions, 2 deletions
diff --git a/src/modules/sidebar/index.tsx b/src/modules/sidebar/index.tsx
index 5ae7670..d4c1855 100644
--- a/src/modules/sidebar/index.tsx
+++ b/src/modules/sidebar/index.tsx
@@ -6,6 +6,7 @@ import Audio from "./audio";
import Connectivity from "./connectivity";
import Dashboard from "./dashboard";
import NotifPane from "./notifpane";
+import Packages from "./packages";
@register()
export default class SideBar extends Widget.Window {
@@ -22,7 +23,7 @@ export default class SideBar extends Widget.Window {
visible: false,
});
- const panes = [<Dashboard />, <Audio />, <Connectivity />, <NotifPane />];
+ const panes = [<Dashboard />, <Audio />, <Connectivity />, <Packages />, <NotifPane />];
this.shown = Variable(panes[0].name);
this.add(
diff --git a/src/modules/sidebar/modules/news.tsx b/src/modules/sidebar/modules/news.tsx
new file mode 100644
index 0000000..f3be53e
--- /dev/null
+++ b/src/modules/sidebar/modules/news.tsx
@@ -0,0 +1,110 @@
+import Palette from "@/services/palette";
+import Updates from "@/services/updates";
+import { setupCustomTooltip } from "@/utils/widgets";
+import { bind, Variable } from "astal";
+import { Gtk } from "astal/gtk3";
+
+const countNews = (news: string) => news.match(/^([0-9]{4}-[0-9]{2}-[0-9]{2} .+)$/gm)?.length ?? 0;
+
+const News = ({ header, body }: { header: string; body: string }) => {
+ const expanded = Variable(false);
+
+ body = body
+ .slice(0, -5) // Remove last unopened \x1b[0m
+ .replaceAll("\x1b[0m", "</span>"); // Replace reset code with end span
+
+ return (
+ <box vertical className="article">
+ <button
+ className="wrapper"
+ cursor="pointer"
+ onClicked={() => expanded.set(!expanded.get())}
+ setup={self => setupCustomTooltip(self, header)}
+ >
+ <box hexpand className="header">
+ <label className="icon" label="newspaper" />
+ <box vertical>
+ <label xalign={0} label={header.split(" ")[0]} />
+ <label
+ truncate
+ xalign={0}
+ className="sublabel"
+ label={header.replace(/[0-9]{4}-[0-9]{2}-[0-9]{2} /, "")}
+ />
+ </box>
+ <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}
+ >
+ <label
+ wrap
+ useMarkup
+ xalign={0}
+ className="body"
+ label={bind(Palette.get_default(), "teal").as(
+ c => body.replaceAll("\x1b[36m", `<span foreground="${c}">`) // Replace colour codes with html spans
+ )}
+ />
+ </revealer>
+ </box>
+ );
+};
+
+const List = () => (
+ <box vertical valign={Gtk.Align.START} className="list">
+ {bind(Updates.get_default(), "news").as(n => {
+ const children = [];
+ const news = n.split(/^([0-9]{4}-[0-9]{2}-[0-9]{2} .+)$/gm);
+ for (let i = 1; i < news.length - 1; i += 2)
+ children.push(<News header={news[i].trim()} body={news[i + 1].trim()} />);
+ return children;
+ })}
+ </box>
+);
+
+const NoNews = () => (
+ <box homogeneous name="empty">
+ <box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className="empty">
+ <label className="icon" label="breaking_news_alt_1" />
+ <label label="No Arch news!" />
+ </box>
+ </box>
+);
+
+export default () => (
+ <box vertical className="news">
+ <box className="header-bar">
+ <label
+ label={bind(Updates.get_default(), "news")
+ .as(countNews)
+ .as(n => `${n} news article${n === 1 ? "" : "s"}`)}
+ />
+ <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(), "news").as(n => (n ? "list" : "empty"))}
+ >
+ <NoNews />
+ <scrollable
+ expand={bind(Updates.get_default(), "news").as(n => !!n)}
+ hscroll={Gtk.PolicyType.NEVER}
+ name="list"
+ >
+ <List />
+ </scrollable>
+ </stack>
+ </box>
+);
diff --git a/src/modules/sidebar/modules/upcoming.tsx b/src/modules/sidebar/modules/upcoming.tsx
index 76dea56..816dff8 100644
--- a/src/modules/sidebar/modules/upcoming.tsx
+++ b/src/modules/sidebar/modules/upcoming.tsx
@@ -82,7 +82,7 @@ export default () => (
sensitive={bind(Calendar.get_default(), "loading").as(l => !l)}
cursor="pointer"
onClicked={() => Calendar.get_default().updateCalendars().catch(console.error)}
- label="󰑓 Reload"
+ label={bind(Calendar.get_default(), "loading").as(l => (l ? "󰑓 Loading" : "󰑓 Reload"))}
/>
</box>
<stack
diff --git a/src/modules/sidebar/packages.tsx b/src/modules/sidebar/packages.tsx
new file mode 100644
index 0000000..97381b1
--- /dev/null
+++ b/src/modules/sidebar/packages.tsx
@@ -0,0 +1,9 @@
+import News from "./modules/news";
+import Updates from "./modules/updates";
+
+export default () => (
+ <box vertical className="pane packages" name="packages">
+ <box className="separator" />
+ <News />
+ </box>
+);