diff options
| -rw-r--r-- | scss/sidebar.scss | 40 | ||||
| -rw-r--r-- | src/modules/sidebar/index.tsx | 3 | ||||
| -rw-r--r-- | src/modules/sidebar/modules/news.tsx | 110 | ||||
| -rw-r--r-- | src/modules/sidebar/modules/upcoming.tsx | 2 | ||||
| -rw-r--r-- | src/modules/sidebar/packages.tsx | 9 |
5 files changed, 162 insertions, 2 deletions
diff --git a/scss/sidebar.scss b/scss/sidebar.scss index 2a71995..2457bfc 100644 --- a/scss/sidebar.scss +++ b/scss/sidebar.scss @@ -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); + } + } + } } 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> +); |