sidebar: package news module

This commit is contained in:
2 * r + 2 * t 2025-03-27 19:20:15 +11:00
parent 93f1dd5131
commit 5d89f8a8d5
5 changed files with 162 additions and 2 deletions

View file

@ -704,4 +704,44 @@
}
}
}
.news {
min-height: lib.s(200);
.empty {
margin-top: lib.s(40);
}
.list {
@include lib.spacing(10, true);
}
.article {
@include lib.rounded(20);
@include lib.element-decel;
background-color: color.change(scheme.$surface1, $alpha: 0.4);
padding: lib.s(10) lib.s(15);
@include lib.spacing(5);
.icon {
font-size: lib.s(28);
&:not(:last-child) {
margin-right: lib.s(12);
}
}
.sublabel {
font-size: lib.s(14);
color: scheme.$subtext0;
}
.body {
margin-top: lib.s(10);
font-size: lib.s(14);
}
}
}
}

View file

@ -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(

View file

@ -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>
);

View file

@ -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

View file

@ -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>
);