feat: add basic bar
This commit is contained in:
parent
864433e39a
commit
af86cc7beb
6 changed files with 170 additions and 54 deletions
6
app.ts
6
app.ts
|
@ -1,10 +1,8 @@
|
||||||
import { App } from "astal/gtk3";
|
import { App } from "astal/gtk4";
|
||||||
import style from "./style.scss";
|
import style from "./style.scss";
|
||||||
import Bar from "./widget/Bar";
|
import Bar from "./widget/Bar";
|
||||||
|
|
||||||
App.start({
|
App.start({
|
||||||
css: style,
|
css: style,
|
||||||
main() {
|
main: () => App.get_monitors().map(Bar),
|
||||||
App.get_monitors().map(Bar);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
18
flake.nix
18
flake.nix
|
@ -17,6 +17,14 @@
|
||||||
}: let
|
}: let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
astalPkgs = with ags.packages.${system}; [
|
||||||
|
battery
|
||||||
|
hyprland
|
||||||
|
mpris
|
||||||
|
network
|
||||||
|
tray
|
||||||
|
wireplumber
|
||||||
|
];
|
||||||
in {
|
in {
|
||||||
packages.${system} = {
|
packages.${system} = {
|
||||||
default = ags.lib.bundle {
|
default = ags.lib.bundle {
|
||||||
|
@ -24,12 +32,10 @@
|
||||||
src = ./.;
|
src = ./.;
|
||||||
name = "coquille";
|
name = "coquille";
|
||||||
entry = "app.ts";
|
entry = "app.ts";
|
||||||
|
gtk4 = true;
|
||||||
|
|
||||||
# additional libraries and executables to add to gjs' runtime
|
# additional libraries and executables to add to gjs' runtime
|
||||||
extraPackages = [
|
extraPackages = astalPkgs;
|
||||||
# ags.packages.${system}.battery
|
|
||||||
# pkgs.fzf
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,9 +44,7 @@
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
# includes astal3 astal4 astal-io by default
|
# includes astal3 astal4 astal-io by default
|
||||||
(ags.packages.${system}.default.override {
|
(ags.packages.${system}.default.override {
|
||||||
extraPackages = [
|
extraPackages = astalPkgs;
|
||||||
# cherry pick packages
|
|
||||||
];
|
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
64
style.scss
64
style.scss
|
@ -1,20 +1,56 @@
|
||||||
// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
|
@use "sass:color";
|
||||||
$fg-color: #{"@theme_fg_color"};
|
@use "sass:string";
|
||||||
$bg-color: #{"@theme_bg_color"};
|
|
||||||
|
@function gtkalpha($c, $a) {
|
||||||
|
@return string.unquote("alpha(#{$c},#{$a})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://gitlab.gnome.org/GNOME/libadwaita/-/blob/main/src/stylesheet/_colors.scss
|
||||||
|
$bg: #{"@window_bg_color"};
|
||||||
|
$fg: #{"@window_fg_color"};
|
||||||
|
$accent: #{"@accent_color"};
|
||||||
|
$radius: 7px;
|
||||||
|
|
||||||
window.Bar {
|
window.Bar {
|
||||||
background: transparent;
|
border: none;
|
||||||
color: $fg-color;
|
box-shadow: none;
|
||||||
font-weight: bold;
|
background-color: $bg;
|
||||||
|
color: $fg;
|
||||||
>centerbox {
|
font-size: 1.2em;
|
||||||
background: $bg-color;
|
padding: 0.5em 0;
|
||||||
border-radius: 10px;
|
|
||||||
margin: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
centerbox {
|
||||||
|
min-height: 2.5em;
|
||||||
|
}
|
||||||
|
.Workspaces {
|
||||||
button {
|
button {
|
||||||
border-radius: 8px;
|
all: unset;
|
||||||
margin: 2px;
|
min-width: 1.1rem;
|
||||||
|
min-height: 1.1rem;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
border: 2px solid $fg;
|
||||||
|
margin: 0.25rem 0.3rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: gtkalpha($accent, 0.6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.focused {
|
||||||
|
border-color: $accent;
|
||||||
|
background-color: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.Battery label {
|
||||||
|
padding-left: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.NotificationCenter {
|
||||||
|
&:hover {
|
||||||
|
background-color: gtkalpha($fg, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "astal/gtk3",
|
"jsxImportSource": "astal/gtk4",
|
||||||
"module": "ES2022",
|
"module": "ES2022",
|
||||||
"moduleResolution": "Bundler",
|
"moduleResolution": "Bundler",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|
110
widget/Bar.tsx
110
widget/Bar.tsx
|
@ -1,31 +1,85 @@
|
||||||
import { App, Astal, Gtk, Gdk } from "astal/gtk3"
|
import { App, Astal, Gtk, Gdk } from "astal/gtk4";
|
||||||
import { Variable } from "astal"
|
import { Variable, GLib, bind } from "astal";
|
||||||
|
import Battery from "gi://AstalBattery";
|
||||||
|
import Wp from "gi://AstalWp";
|
||||||
|
import Network from "gi://AstalNetwork";
|
||||||
|
import { Workspaces } from "./Workspaces";
|
||||||
|
|
||||||
const time = Variable("").poll(1000, "date")
|
function Wifi() {
|
||||||
|
const network = Network.get_default();
|
||||||
|
const wifi = bind(network, "wifi");
|
||||||
|
|
||||||
export default function Bar(gdkmonitor: Gdk.Monitor) {
|
return (
|
||||||
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
|
<box visible={wifi.as(Boolean)}>
|
||||||
|
{wifi.as(
|
||||||
return <window
|
(wifi) =>
|
||||||
className="Bar"
|
wifi && (
|
||||||
gdkmonitor={gdkmonitor}
|
<image cssClasses={["Wifi"]} iconName={bind(wifi, "iconName")} />
|
||||||
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
),
|
||||||
anchor={TOP | LEFT | RIGHT}
|
)}
|
||||||
application={App}>
|
</box>
|
||||||
<centerbox>
|
);
|
||||||
<button
|
}
|
||||||
onClicked="echo hello"
|
|
||||||
halign={Gtk.Align.CENTER}
|
function Audio() {
|
||||||
>
|
const speaker = Wp.get_default()?.audio.defaultSpeaker!;
|
||||||
Welcome to AGS!
|
|
||||||
</button>
|
return (
|
||||||
<box />
|
<box cssClasses={["AudioSlider"]}>
|
||||||
<button
|
<image iconName={bind(speaker, "volumeIcon")} />
|
||||||
onClicked={() => print("hello")}
|
</box>
|
||||||
halign={Gtk.Align.CENTER}
|
);
|
||||||
>
|
}
|
||||||
<label label={time()} />
|
|
||||||
</button>
|
function BatteryLevel() {
|
||||||
</centerbox>
|
const bat = Battery.get_default();
|
||||||
</window>
|
|
||||||
|
return (
|
||||||
|
<box cssClasses={["Battery"]} visible={bind(bat, "isPresent")}>
|
||||||
|
<image iconName={bind(bat, "batteryIconName")} />
|
||||||
|
<label
|
||||||
|
label={bind(bat, "percentage").as((p) => `${Math.floor(p * 100)} %`)}
|
||||||
|
/>
|
||||||
|
</box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Time({ format = "%H:%M - %A %e." }) {
|
||||||
|
const time = Variable<string>("").poll(
|
||||||
|
1000,
|
||||||
|
() => GLib.DateTime.new_now_local().format(format)!,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label cssClasses={["Time"]} onDestroy={() => time.drop()} label={time()} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Bar(monitor: Gdk.Monitor) {
|
||||||
|
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<window
|
||||||
|
visible
|
||||||
|
namespace={"bar"}
|
||||||
|
cssClasses={["Bar"]}
|
||||||
|
gdkmonitor={monitor}
|
||||||
|
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
||||||
|
anchor={TOP | LEFT | RIGHT}
|
||||||
|
>
|
||||||
|
<centerbox>
|
||||||
|
<box hexpand halign={Gtk.Align.START}>
|
||||||
|
<Workspaces />
|
||||||
|
</box>
|
||||||
|
<box>
|
||||||
|
<Time />
|
||||||
|
</box>
|
||||||
|
<box cssClasses={["NotificationCenter"]} hexpand halign={Gtk.Align.END}>
|
||||||
|
<Audio />
|
||||||
|
<Wifi />
|
||||||
|
<BatteryLevel />
|
||||||
|
</box>
|
||||||
|
</centerbox>
|
||||||
|
</window>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
24
widget/Workspaces.tsx
Normal file
24
widget/Workspaces.tsx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { bind } from "astal";
|
||||||
|
import Hyprland from "gi://AstalHyprland";
|
||||||
|
|
||||||
|
export const Workspaces = () => {
|
||||||
|
const hypr = Hyprland.get_default();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<box cssClasses={["Workspaces"]}>
|
||||||
|
{bind(hypr, "workspaces").as((wss) =>
|
||||||
|
wss
|
||||||
|
.filter((ws) => !(ws.id >= -99 && ws.id <= -2)) // filter out special workspaces
|
||||||
|
.sort((a, b) => a.id - b.id)
|
||||||
|
.map((ws) => (
|
||||||
|
<button
|
||||||
|
cssClasses={bind(hypr, "focusedWorkspace").as((fw) =>
|
||||||
|
ws === fw ? ["focused"] : [""],
|
||||||
|
)}
|
||||||
|
onClicked={() => ws.focus()}
|
||||||
|
></button>
|
||||||
|
)),
|
||||||
|
)}
|
||||||
|
</box>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue