summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app.ts12
-rw-r--r--style.scss48
-rw-r--r--widget/Bar.tsx124
3 files changed, 136 insertions, 48 deletions
diff --git a/app.ts b/app.ts
index 7e8cc7c..b6bf451 100644
--- a/app.ts
+++ b/app.ts
@@ -2,9 +2,13 @@ import { App } from "astal/gtk4"
import style from "./style.scss"
import Bar from "./widget/Bar"
+const windows = [
+ Bar,
+]
+
App.start({
- css: style,
- main() {
- App.get_monitors().map(Bar)
- },
+ css: style,
+ main() {
+ windows.forEach(window => App.get_monitors().map(window))
+ },
})
diff --git a/style.scss b/style.scss
index 1d0d3a9..08bcbbf 100644
--- a/style.scss
+++ b/style.scss
@@ -1,20 +1,42 @@
// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
-$fg-color: #{"@theme_fg_color"};
-$bg-color: #{"@theme_bg_color"};
+// $fg-color: #{"@theme_fg_color"};
+// $bg-color: #{"@theme_bg_color"};
window.Bar {
- background: transparent;
- color: $fg-color;
- font-weight: bold;
-
- >centerbox {
- background: $bg-color;
- border-radius: 10px;
- margin: 8px;
+ border: none;
+ box-shadow: none;
+ background-color: #000;
+ color: #fff;
+
+ >box {
+ padding: 4px 0;
+ }
+}
+
+box.Workspaces {
+ padding-left: 3px;
+
+ >button {
+ min-width: 10px;
+ min-height: 10px;
+ border-radius: 5px;
+
+ border: none;
+ margin: 2px 4px;
+ padding: 0;
+ background: #ccc;
+
+ transition: min-width 2s ease-in-out;
+ // transition-property: min-width;
+ // transition-duration: 2s;
+ // transition-timing-function: ease-out;
+
+ &.active {
+ min-width: 25px;
}
- button {
- border-radius: 8px;
- margin: 2px;
+ &.focused {
+ background: #AD49E1;
}
+ }
}
diff --git a/widget/Bar.tsx b/widget/Bar.tsx
index c2db8c5..02aa3ba 100644
--- a/widget/Bar.tsx
+++ b/widget/Bar.tsx
@@ -1,36 +1,98 @@
import { App, Astal, Gtk, Gdk } from "astal/gtk4"
-import { Variable } from "astal"
+import { exec, GLib, Variable } from "astal"
+
+type NiriWorkspace = {
+ id: number,
+ idx: number,
+ name: string | null,
+ output: string,
+ is_active: boolean,
+ is_focused: boolean,
+ active_window_id: number | null,
+};
+
+function getWorkspaces(): NiriWorkspace[] {
+ // NOTE: this works only in non-systemd environment on NixOS
+ // TODO: try to use Niri socket if it is documented
+ return JSON.parse(exec("niri msg -j workspaces"));
+}
+
+function getWorkspacesByOutput(output: string): NiriWorkspace[] {
+ return getWorkspaces().filter(workspace => workspace.output == output).sort((a, b) => a.idx - b.idx);
+}
+
+function focusWorkspace(idx: number) {
+ // NOTE: this works only in non-systemd environment on NixOS
+ // TODO: try to use Niri socket if it is documented
+ exec(`niri msg action focus-workspace ${idx}`);
+}
+
+type WorkspaceButtonArguments = {
+ idx: number,
+ isActive: boolean,
+ isFocused: boolean,
+};
+
+function WorkspaceButton(args: WorkspaceButtonArguments) {
+ const classes: string[] = [];
+ args.isActive && classes.push("active");
+ args.isFocused && classes.push("focused");
+ return <button cssClasses={classes} onClicked={() => focusWorkspace(args.idx)} />
+}
+
+type WorkspacesArguments = {
+ connector: string,
+};
+
+function Workspaces(args: WorkspacesArguments) {
+ // NOTE: it is pretty inefficient and not so much responsive
+ // TODO: it would be better to use Niri socket in the future
+ const workspaces: Variable<NiriWorkspace[]> = Variable(getWorkspacesByOutput(args.connector))
+ .poll(1000, () => getWorkspacesByOutput(args.connector));
+
+ // BUG: on workspace change there's no CSS transition
+ // I guess it is due to rerender here
+ return <box cssClasses={["Workspaces"]}>
+ {workspaces(v => v.map(workspace => <WorkspaceButton idx={workspace.idx} isActive={workspace.is_active} isFocused={workspace.is_focused} />))}
+ </box>
+}
+
+
+type TimeArguments = {
+ format: string,
+};
+
+function Time(args: TimeArguments) {
+ const time = Variable<GLib.DateTime>(GLib.DateTime.new_now_local()).poll(1000, () => GLib.DateTime.new_now_local())
+
+ return <box>
+ {time(v => v.format(args.format))}
+ </box>
+}
-const time = Variable("").poll(1000, "date")
export default function Bar(gdkmonitor: Gdk.Monitor) {
- const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
-
- return <window
- visible
- cssClasses={["Bar"]}
- gdkmonitor={gdkmonitor}
- exclusivity={Astal.Exclusivity.EXCLUSIVE}
- anchor={TOP | LEFT | RIGHT}
- application={App}>
- <centerbox cssName="centerbox">
- <button
- onClicked="echo hello"
- hexpand
- halign={Gtk.Align.CENTER}
- >
- Welcome to AGS!
- </button>
- <box />
- <menubutton
- hexpand
- halign={Gtk.Align.CENTER}
- >
- <label label={time()} />
- <popover>
- <Gtk.Calendar />
- </popover>
- </menubutton>
- </centerbox>
- </window>
+ const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
+
+ return <window
+ visible
+ name={"Bar"}
+ cssClasses={["Bar"]}
+ gdkmonitor={gdkmonitor}
+ exclusivity={Astal.Exclusivity.EXCLUSIVE}
+ anchor={TOP | LEFT | RIGHT}
+ application={App}>
+ <centerbox cssClasses={["bar-container"]}>
+ <box halign={Gtk.Align.START}>
+ <Workspaces connector={gdkmonitor.get_connector()!} />
+ </box>
+
+ <box halign={Gtk.Align.CENTER}>
+ </box>
+
+ <box halign={Gtk.Align.END}>
+ <Time format="%I:%M:%S %p %Z" />
+ </box>
+ </centerbox>
+ </window>
}