bar: vertical mode
This commit is contained in:
parent
f7077ac51e
commit
0b771cbd1b
5 changed files with 164 additions and 68 deletions
|
|
@ -2,7 +2,8 @@ import { Astal } from "astal/gtk3";
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
export const bar = {
|
export const bar = {
|
||||||
wsPerGroup: 10,
|
vertical: true,
|
||||||
|
wsPerGroup: 5,
|
||||||
dateTimeFormat: "%d/%m/%y %R",
|
dateTimeFormat: "%d/%m/%y %R",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
147
scss/bar.scss
147
scss/bar.scss
|
|
@ -6,22 +6,12 @@
|
||||||
.bar {
|
.bar {
|
||||||
@include font.mono;
|
@include font.mono;
|
||||||
|
|
||||||
margin: 10px 10px 0 10px;
|
|
||||||
font-size: lib.s(14);
|
font-size: lib.s(14);
|
||||||
|
|
||||||
@include lib.spacing(10);
|
|
||||||
|
|
||||||
& > * {
|
|
||||||
@include lib.spacing(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
.module {
|
.module {
|
||||||
@include lib.rounded(8);
|
@include lib.rounded(8);
|
||||||
|
|
||||||
padding: lib.s(3) lib.s(8);
|
|
||||||
background-color: scheme.$base;
|
background-color: scheme.$base;
|
||||||
|
|
||||||
@include lib.spacing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
label.icon {
|
label.icon {
|
||||||
|
|
@ -33,7 +23,6 @@
|
||||||
|
|
||||||
color: scheme.$yellow;
|
color: scheme.$yellow;
|
||||||
font-size: lib.s(14);
|
font-size: lib.s(14);
|
||||||
padding-right: lib.s(12);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.active-window {
|
.active-window {
|
||||||
|
|
@ -43,55 +32,35 @@
|
||||||
.media-playing {
|
.media-playing {
|
||||||
color: scheme.$lavender;
|
color: scheme.$lavender;
|
||||||
|
|
||||||
@include lib.spacing(8);
|
|
||||||
|
|
||||||
icon {
|
icon {
|
||||||
font-size: lib.s(16);
|
font-size: lib.s(16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspaces {
|
.workspaces > * {
|
||||||
padding: lib.s(3) lib.s(18);
|
@include lib.rounded(100);
|
||||||
|
@include lib.element-decel;
|
||||||
|
|
||||||
@include lib.spacing(10);
|
min-width: lib.s(8);
|
||||||
|
min-height: lib.s(8);
|
||||||
|
background-color: scheme.$surface1;
|
||||||
|
|
||||||
& > * {
|
&.occupied {
|
||||||
@include lib.rounded(100);
|
background-color: scheme.$overlay1;
|
||||||
@include lib.element-decel;
|
}
|
||||||
|
|
||||||
min-width: lib.s(8);
|
&.focused {
|
||||||
min-height: lib.s(8);
|
background-color: scheme.$mauve;
|
||||||
background-color: scheme.$surface1;
|
|
||||||
|
|
||||||
&.occupied {
|
|
||||||
background-color: scheme.$overlay1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.focused {
|
|
||||||
min-width: lib.s(30);
|
|
||||||
background-color: scheme.$mauve;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tray {
|
.tray {
|
||||||
font-size: lib.s(15);
|
font-size: lib.s(15);
|
||||||
color: scheme.$text;
|
color: scheme.$text;
|
||||||
|
|
||||||
@include lib.spacing(10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-icons {
|
.status-icons {
|
||||||
color: scheme.$rosewater;
|
color: scheme.$rosewater;
|
||||||
|
|
||||||
.bluetooth {
|
|
||||||
@include lib.spacing(10);
|
|
||||||
|
|
||||||
// The spacing doesn't look right for some reason so this
|
|
||||||
& > :first-child:not(:last-child) {
|
|
||||||
margin-right: lib.s(5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pkg-updates {
|
.pkg-updates {
|
||||||
|
|
@ -123,4 +92,98 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: lib.s(16);
|
font-size: lib.s(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.horizontal {
|
||||||
|
margin: 10px 10px 0 10px;
|
||||||
|
|
||||||
|
@include lib.spacing(10);
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
@include lib.spacing(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module {
|
||||||
|
padding: lib.s(3) lib.s(8);
|
||||||
|
|
||||||
|
@include lib.spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-icon {
|
||||||
|
padding-right: lib.s(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-playing {
|
||||||
|
@include lib.spacing(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspaces {
|
||||||
|
padding: lib.s(3) lib.s(18);
|
||||||
|
|
||||||
|
@include lib.spacing(10);
|
||||||
|
|
||||||
|
& > .focused {
|
||||||
|
min-width: lib.s(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tray {
|
||||||
|
@include lib.spacing(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icons .bluetooth {
|
||||||
|
@include lib.spacing(10);
|
||||||
|
|
||||||
|
// The spacing doesn't look right for some reason so this
|
||||||
|
& > :first-child:not(:last-child) {
|
||||||
|
margin-right: lib.s(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vertical {
|
||||||
|
margin: 10px 0 10px 10px;
|
||||||
|
|
||||||
|
@include lib.spacing(10, true);
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
@include lib.spacing(10, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module {
|
||||||
|
padding: lib.s(8);
|
||||||
|
|
||||||
|
@include lib.spacing($vertical: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-icon > * {
|
||||||
|
margin-left: lib.s(-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-playing {
|
||||||
|
@include lib.spacing(8, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspaces {
|
||||||
|
padding: lib.s(18) lib.s(3);
|
||||||
|
|
||||||
|
@include lib.spacing(10, true);
|
||||||
|
|
||||||
|
& > .focused {
|
||||||
|
min-height: lib.s(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tray {
|
||||||
|
@include lib.spacing(10, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icons .bluetooth {
|
||||||
|
@include lib.spacing(10, true);
|
||||||
|
|
||||||
|
// The spacing doesn't look right for some reason so this
|
||||||
|
& > :first-child:not(:last-child) {
|
||||||
|
margin-bottom: lib.s(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,14 +68,15 @@ const togglePopup = (self: JSX.Element, event: Astal.ClickEvent, name: string) =
|
||||||
const OSIcon = () => (
|
const OSIcon = () => (
|
||||||
<button
|
<button
|
||||||
className="module os-icon"
|
className="module os-icon"
|
||||||
label={osIcon}
|
|
||||||
onClick={(self, event) => event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "sideleft")}
|
onClick={(self, event) => event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "sideleft")}
|
||||||
/>
|
>
|
||||||
|
{osIcon}
|
||||||
|
</button>
|
||||||
);
|
);
|
||||||
|
|
||||||
const ActiveWindow = () => (
|
const ActiveWindow = () => (
|
||||||
<box
|
<box
|
||||||
hasTooltip
|
vertical={config.vertical}
|
||||||
className="module active-window"
|
className="module active-window"
|
||||||
setup={self => {
|
setup={self => {
|
||||||
const title = Variable("");
|
const title = Variable("");
|
||||||
|
|
@ -101,8 +102,13 @@ const ActiveWindow = () => (
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
|
angle={config.vertical ? 270 : 0}
|
||||||
setup={self =>
|
setup={self =>
|
||||||
hookFocusedClientProp(self, "title", c => (self.label = c?.title ? ellipsize(c.title) : "Desktop"))
|
hookFocusedClientProp(
|
||||||
|
self,
|
||||||
|
"title",
|
||||||
|
c => (self.label = c?.title ? ellipsize(c.title, config.vertical ? 30 : 40) : "Desktop")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -126,7 +132,7 @@ const MediaPlaying = () => {
|
||||||
setupCustomTooltip(self, bind(label));
|
setupCustomTooltip(self, bind(label));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<box className="module media-playing">
|
<box vertical={config.vertical} className="module media-playing">
|
||||||
<icon
|
<icon
|
||||||
setup={self =>
|
setup={self =>
|
||||||
players.hookLastPlayer(self, "notify::identity", () => {
|
players.hookLastPlayer(self, "notify::identity", () => {
|
||||||
|
|
@ -142,6 +148,7 @@ const MediaPlaying = () => {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
|
angle={config.vertical ? 270 : 0}
|
||||||
setup={self =>
|
setup={self =>
|
||||||
players.hookLastPlayer(self, ["notify::title", "notify::artist"], () => {
|
players.hookLastPlayer(self, ["notify::title", "notify::artist"], () => {
|
||||||
self.label = ellipsize(getLabel("No media")); // TODO: scroll text
|
self.label = ellipsize(getLabel("No media")); // TODO: scroll text
|
||||||
|
|
@ -195,7 +202,7 @@ const Workspaces = () => (
|
||||||
hyprland.dispatch("workspace", (event.delta_y < 0 ? "-" : "+") + 1);
|
hyprland.dispatch("workspace", (event.delta_y < 0 ? "-" : "+") + 1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<box className="module workspaces">
|
<box vertical={config.vertical} className="module workspaces">
|
||||||
{Array.from({ length: config.wsPerGroup }).map((_, idx) => (
|
{Array.from({ length: config.wsPerGroup }).map((_, idx) => (
|
||||||
<Workspace idx={idx + 1} /> // Start from 1
|
<Workspace idx={idx + 1} /> // Start from 1
|
||||||
))}
|
))}
|
||||||
|
|
@ -248,7 +255,11 @@ const TrayItem = (item: AstalTray.TrayItem) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Tray = () => (
|
const Tray = () => (
|
||||||
<box className="module tray" visible={bind(AstalTray.get_default(), "items").as(i => i.length > 0)}>
|
<box
|
||||||
|
vertical={config.vertical}
|
||||||
|
className="module tray"
|
||||||
|
visible={bind(AstalTray.get_default(), "items").as(i => i.length > 0)}
|
||||||
|
>
|
||||||
{bind(AstalTray.get_default(), "items").as(i => i.map(TrayItem))}
|
{bind(AstalTray.get_default(), "items").as(i => i.map(TrayItem))}
|
||||||
</box>
|
</box>
|
||||||
);
|
);
|
||||||
|
|
@ -378,7 +389,7 @@ const BluetoothDevice = (device: AstalBluetooth.Device) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
const Bluetooth = () => (
|
const Bluetooth = () => (
|
||||||
<box className="bluetooth">
|
<box vertical={config.vertical} className="bluetooth">
|
||||||
<button
|
<button
|
||||||
onClick={(self, event) => {
|
onClick={(self, event) => {
|
||||||
if (event.button === Astal.MouseButton.PRIMARY) togglePopup(self, event, "bluetooth-devices");
|
if (event.button === Astal.MouseButton.PRIMARY) togglePopup(self, event, "bluetooth-devices");
|
||||||
|
|
@ -424,7 +435,7 @@ const Bluetooth = () => (
|
||||||
);
|
);
|
||||||
|
|
||||||
const StatusIcons = () => (
|
const StatusIcons = () => (
|
||||||
<box className="module status-icons">
|
<box vertical={config.vertical} className="module status-icons">
|
||||||
<Network />
|
<Network />
|
||||||
<Bluetooth />
|
<Bluetooth />
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -440,7 +451,7 @@ const PkgUpdates = () => (
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<box className="module pkg-updates">
|
<box vertical={config.vertical} className="module pkg-updates">
|
||||||
<label className="icon" label="download" />
|
<label className="icon" label="download" />
|
||||||
<label label={bind(Updates.get_default(), "numUpdates").as(String)} />
|
<label label={bind(Updates.get_default(), "numUpdates").as(String)} />
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -461,7 +472,7 @@ const NotifCount = () => (
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<box className="module notif-count">
|
<box vertical={config.vertical} className="module notif-count">
|
||||||
<label className="icon" label="info" />
|
<label className="icon" label="info" />
|
||||||
<label label={bind(AstalNotifd.get_default(), "notifications").as(n => String(n.length))} />
|
<label label={bind(AstalNotifd.get_default(), "notifications").as(n => String(n.length))} />
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -476,6 +487,7 @@ const Battery = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box
|
<box
|
||||||
|
vertical={config.vertical}
|
||||||
className={bind(className)}
|
className={bind(className)}
|
||||||
setup={self =>
|
setup={self =>
|
||||||
setupCustomTooltip(
|
setupCustomTooltip(
|
||||||
|
|
@ -486,7 +498,9 @@ const Battery = () => {
|
||||||
onDestroy={() => className.drop()}
|
onDestroy={() => className.drop()}
|
||||||
>
|
>
|
||||||
<revealer
|
<revealer
|
||||||
transitionType={Gtk.RevealerTransitionType.SLIDE_RIGHT}
|
transitionType={
|
||||||
|
config.vertical ? Gtk.RevealerTransitionType.SLIDE_UP : Gtk.RevealerTransitionType.SLIDE_LEFT
|
||||||
|
}
|
||||||
transitionDuration={150}
|
transitionDuration={150}
|
||||||
revealChild={bind(AstalBattery.get_default(), "charging")}
|
revealChild={bind(AstalBattery.get_default(), "charging")}
|
||||||
>
|
>
|
||||||
|
|
@ -502,9 +516,9 @@ const DateTime = () => (
|
||||||
<button
|
<button
|
||||||
onClick={(self, event) => event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "sideright")}
|
onClick={(self, event) => event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "sideright")}
|
||||||
>
|
>
|
||||||
<box className="module date-time">
|
<box vertical={config.vertical} className="module date-time">
|
||||||
<label className="icon" label="calendar_month" />
|
<label className="icon" label="calendar_month" />
|
||||||
<label label={bindCurrentTime(config.dateTimeFormat)} />
|
<label angle={config.vertical ? 270 : 0} label={bindCurrentTime(config.dateTimeFormat)} />
|
||||||
</box>
|
</box>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
@ -521,25 +535,29 @@ export default ({ monitor }: { monitor: Monitor }) => (
|
||||||
<window
|
<window
|
||||||
namespace="caelestia-bar"
|
namespace="caelestia-bar"
|
||||||
monitor={monitor.id}
|
monitor={monitor.id}
|
||||||
anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT}
|
anchor={
|
||||||
|
Astal.WindowAnchor.TOP |
|
||||||
|
Astal.WindowAnchor.LEFT |
|
||||||
|
(config.vertical ? Astal.WindowAnchor.BOTTOM : Astal.WindowAnchor.RIGHT)
|
||||||
|
}
|
||||||
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
||||||
>
|
>
|
||||||
<centerbox className="bar">
|
<centerbox vertical={config.vertical} className={`bar ${config.vertical ? "vertical" : " horizontal"}`}>
|
||||||
<box>
|
<box vertical={config.vertical}>
|
||||||
<OSIcon />
|
<OSIcon />
|
||||||
<ActiveWindow />
|
<ActiveWindow />
|
||||||
<MediaPlaying />
|
<MediaPlaying />
|
||||||
<button
|
<button
|
||||||
hexpand
|
expand
|
||||||
onScroll={(_, event) =>
|
onScroll={(_, event) =>
|
||||||
event.delta_y > 0 ? (monitor.brightness -= 0.1) : (monitor.brightness += 0.1)
|
event.delta_y > 0 ? (monitor.brightness -= 0.1) : (monitor.brightness += 0.1)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
<Workspaces />
|
<Workspaces />
|
||||||
<box>
|
<box vertical={config.vertical}>
|
||||||
<button
|
<button
|
||||||
hexpand
|
expand
|
||||||
onScroll={(_, event) => {
|
onScroll={(_, event) => {
|
||||||
const speaker = AstalWp01.get_default()?.audio.defaultSpeaker;
|
const speaker = AstalWp01.get_default()?.audio.defaultSpeaker;
|
||||||
if (!speaker) return;
|
if (!speaker) return;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import type { AstalWidget } from "./types";
|
||||||
export const setupCustomTooltip = (self: AstalWidget, text: string | Binding<string>) => {
|
export const setupCustomTooltip = (self: AstalWidget, text: string | Binding<string>) => {
|
||||||
if (!text) return null;
|
if (!text) return null;
|
||||||
|
|
||||||
|
self.set_has_tooltip(true);
|
||||||
|
|
||||||
const window = new Widget.Window({
|
const window = new Widget.Window({
|
||||||
visible: false,
|
visible: false,
|
||||||
namespace: "caelestia-tooltip",
|
namespace: "caelestia-tooltip",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Binding, register } from "astal";
|
import { Binding, register } from "astal";
|
||||||
import { App, Astal, Gdk, Widget } from "astal/gtk3";
|
import { App, Astal, Gdk, Widget } from "astal/gtk3";
|
||||||
|
import { bar } from "config";
|
||||||
import AstalHyprland from "gi://AstalHyprland?version=0.1";
|
import AstalHyprland from "gi://AstalHyprland?version=0.1";
|
||||||
|
|
||||||
const extendProp = <T>(
|
const extendProp = <T>(
|
||||||
|
|
@ -29,19 +30,30 @@ export default class PopupWindow extends Widget.Window {
|
||||||
|
|
||||||
popup_at_widget(widget: JSX.Element, event: Gdk.Event | Astal.ClickEvent) {
|
popup_at_widget(widget: JSX.Element, event: Gdk.Event | Astal.ClickEvent) {
|
||||||
const { width, height } = widget.get_allocation();
|
const { width, height } = widget.get_allocation();
|
||||||
const mWidth = AstalHyprland.get_default().get_focused_monitor().get_width();
|
const { width: mWidth, height: mHeight } = AstalHyprland.get_default().get_focused_monitor();
|
||||||
const pWidth = this.get_preferred_width()[1];
|
const pWidth = this.get_preferred_width()[1];
|
||||||
|
const pHeight = this.get_preferred_height()[1];
|
||||||
const [, x, y] = event instanceof Gdk.Event ? event.get_coords() : [null, event.x, event.y];
|
const [, x, y] = event instanceof Gdk.Event ? event.get_coords() : [null, event.x, event.y];
|
||||||
const { x: cx, y: cy } = AstalHyprland.get_default().get_cursor_position();
|
const { x: cx, y: cy } = AstalHyprland.get_default().get_cursor_position();
|
||||||
|
|
||||||
let marginLeft = cx + ((width - pWidth) / 2 - x);
|
let marginLeft = 0;
|
||||||
if (marginLeft < 0) marginLeft = 0;
|
let marginTop = 0;
|
||||||
else if (marginLeft + pWidth > mWidth) marginLeft = mWidth - pWidth;
|
if (bar.vertical) {
|
||||||
|
marginLeft = cx + (width - x);
|
||||||
|
marginTop = cy + ((height - pHeight) / 2 - y);
|
||||||
|
if (marginTop < 0) marginTop = 0;
|
||||||
|
else if (marginTop + pHeight > mHeight) marginTop = mHeight - pHeight;
|
||||||
|
} else {
|
||||||
|
marginLeft = cx + ((width - pWidth) / 2 - x);
|
||||||
|
if (marginLeft < 0) marginLeft = 0;
|
||||||
|
else if (marginLeft + pWidth > mWidth) marginLeft = mWidth - pWidth;
|
||||||
|
marginTop = cy + (height - y);
|
||||||
|
}
|
||||||
|
|
||||||
this.anchor = Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT;
|
this.anchor = Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT;
|
||||||
this.exclusivity = Astal.Exclusivity.IGNORE;
|
this.exclusivity = Astal.Exclusivity.IGNORE;
|
||||||
this.marginLeft = marginLeft;
|
this.marginLeft = marginLeft;
|
||||||
this.marginTop = cy + (height - y);
|
this.marginTop = marginTop;
|
||||||
|
|
||||||
this.show();
|
this.show();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue