diff --git a/ags/style/_bar.scss b/ags/style/_bar.scss index 27f8cad..240a367 100644 --- a/ags/style/_bar.scss +++ b/ags/style/_bar.scss @@ -58,7 +58,7 @@ & button { border-radius: 16px; transition: 80ms linear; - min-width: 12px; + min-width: 15px; padding: 0 6px; background: colors.$bg-tertiary; margin: 3px 0; @@ -144,14 +144,13 @@ box-shadow: inset 0 0 0 300px rgba(colors.$fg-primary, .2); } - & .nf { - margin-right: 4px; + & .icon { font-size: 14px; } & .media-controls { transition: none; - padding: 0 6px; + margin-left: 6px; border-top-right-radius: 12px; border-bottom-right-radius: 12px; @@ -169,13 +168,8 @@ & .media > box { border-top-right-radius: 0; border-bottom-right-radius: 0; - padding: 0 6px; } - & .media { - padding-left: 0; - padding-right: 0; - } } } diff --git a/ags/style/_center-window.scss b/ags/style/_center-window.scss index 1977dae..32501eb 100644 --- a/ags/style/_center-window.scss +++ b/ags/style/_center-window.scss @@ -68,7 +68,7 @@ } } - & .left .top { + & .left .datetime { padding-bottom: 10px; & .time { diff --git a/ags/widget/Separator.ts b/ags/widget/Separator.ts index 5d9b130..34c50de 100644 --- a/ags/widget/Separator.ts +++ b/ags/widget/Separator.ts @@ -7,40 +7,50 @@ export interface SeparatorProps { cssColor?: string; orientation?: Gtk.Orientation; size?: number; + spacing?: number; + margin?: number; visible?: boolean | Binding; } -export function Separator(props: SeparatorProps) { +export function Separator(props: SeparatorProps = { + orientation: Gtk.Orientation.HORIZONTAL +}) { props.alpha = props.alpha ? (props.alpha > 1 ? props.alpha / 100 : props.alpha) : 1; + props.orientation = props.orientation ?? Gtk.Orientation.HORIZONTAL; + return new Widget.Box({ name: "separator", + ...(props.orientation === Gtk.Orientation.HORIZONTAL ? + { vexpand: true } : { hexpand: true }), className: `separator ${ props.orientation === Gtk.Orientation.VERTICAL ? "vertical" : "horizontal" }`, visible: props.visible, css: `.vertical { - padding: 7px 7px; + padding: ${props.spacing ?? 0}px ${props.margin ?? 7}px; } .horizontal { - padding: 4px 4px; + padding: ${props.margin ?? 4}px ${props.spacing ?? 0}px; }`, child: new Widget.Box({ className: `${ props.orientation === Gtk.Orientation.VERTICAL ? "vertical" : "horizontal" } ${ props.class ? props.class : "" }`, + ...(props.orientation === Gtk.Orientation.HORIZONTAL ? + { vexpand: true } : { hexpand: true }), css: `* { - background: ${ props.cssColor || "lightgray" }; + background: ${ props.cssColor ?? "lightgray" }; opacity: ${props.alpha}; } .horizontal { - min-width: ${ props.size || 1 }px; + min-width: ${ props.size ?? 1 }px; } .vertical { - min-height: ${ props.size || 1 }px; + min-height: ${ props.size ?? 1 }px; }` } as Widget.BoxProps) } as Widget.BoxProps); diff --git a/ags/widget/bar/FocusedClient.ts b/ags/widget/bar/FocusedClient.ts index a2ee4ea..30ef0cf 100644 --- a/ags/widget/bar/FocusedClient.ts +++ b/ags/widget/bar/FocusedClient.ts @@ -9,44 +9,42 @@ export function FocusedClient(): Gtk.Widget { return new Widget.Box({ className: "focused-client", visible: bind(hyprland, "focusedClient").as(Boolean), - children: [ + children: bind(hyprland, "focusedClient").as(focusedClient => focusedClient ? [ new Widget.Icon({ className: "icon", vexpand: true, css: ".icon { font-size: 18px; }", - icon: bind(hyprland, "focusedClient").as((client: AstalHyprland.Client) => - client ? getAppIcon(client.initialClass) : "image-missing") + icon: bind(focusedClient, "class").as(clss => + getAppIcon(clss) ?? "application-x-executable-symbolic") }), new Widget.Box({ className: "text-content", orientation: Gtk.Orientation.VERTICAL, homogeneous: false, valign: Gtk.Align.CENTER, - children: bind(hyprland, "focusedClient").as((focusedClient: AstalHyprland.Client) => - focusedClient ? [ - new Widget.Label({ - className: "class", - xalign: 0, - visible: bind(focusedClient, "class").as(Boolean), - maxWidthChars: 55, - truncate: true, - tooltipText: bind(focusedClient, "class").as((clientClass: string) => - clientClass.length > 55 ? clientClass : ""), - label: bind(focusedClient, "class") - } as Widget.LabelProps), - new Widget.Label({ - className: "title", - xalign: 0, - maxWidthChars: 50, - visible: bind(focusedClient, "title").as(Boolean), - truncate: true, - tooltipText: bind(focusedClient, "title").as((clientTitle: string) => - clientTitle.length > 55 ? clientTitle : ""), - label: bind(focusedClient, "title") - } as Widget.LabelProps) - ] : [] - ) + children: [ + new Widget.Label({ + className: "class", + xalign: 0, + visible: bind(focusedClient, "class").as(Boolean), + maxWidthChars: 55, + truncate: true, + tooltipText: bind(focusedClient, "class").as((clientClass: string) => + clientClass.length > 55 ? clientClass : ""), + label: bind(focusedClient, "class") + } as Widget.LabelProps), + new Widget.Label({ + className: "title", + xalign: 0, + maxWidthChars: 50, + visible: bind(focusedClient, "title").as(Boolean), + truncate: true, + tooltipText: bind(focusedClient, "title").as((clientTitle: string) => + clientTitle.length > 55 ? clientTitle : ""), + label: bind(focusedClient, "title") + } as Widget.LabelProps) + ] }) - ] + ]: []) } as Widget.BoxProps); } diff --git a/ags/widget/bar/Media.ts b/ags/widget/bar/Media.ts index 5206d7d..2b43872 100644 --- a/ags/widget/bar/Media.ts +++ b/ags/widget/bar/Media.ts @@ -2,10 +2,8 @@ import { bind, execAsync, GLib } from "astal"; import { Gtk, Widget } from "astal/gtk3"; import AstalMpris from "gi://AstalMpris"; import { Separator, SeparatorProps } from "../Separator"; -import { CenterWindow } from "../../window/CenterWindow"; import { Windows } from "../../windows"; -const mpris: AstalMpris.Mpris = AstalMpris.get_default(); const playerIcons = { spotify: '󰓇', @@ -16,8 +14,8 @@ const playerIcons = { } export function Media(): Gtk.Widget { - let hoverConnectionId: number; - let hoverLostConnectionId: number; + + const connections: Array = []; const mediaControlsRevealer: Widget.Revealer = new Widget.Revealer({ transitionType: Gtk.RevealerTransitionType.SLIDE_RIGHT, @@ -27,7 +25,7 @@ export function Media(): Gtk.Widget { className: "media-controls button-row", expand: false, homogeneous: false, - children: bind(mpris, "players").as((players: Array) => + children: bind(AstalMpris.get_default(), "players").as((players: Array) => players[0] ? [ new Widget.Button({ className: "link nf", @@ -71,21 +69,16 @@ export function Media(): Gtk.Widget { const mediaWidget = new Widget.EventBox({ className: "media-eventbox", - visible: bind(mpris, "players").as((players: Array) => + visible: bind(AstalMpris.get_default(), "players").as((players: Array) => players[0] && players[0].get_available()), - onDestroy: (_) => { - hoverConnectionId !== undefined && - _.disconnect(hoverConnectionId); - - hoverLostConnectionId !== undefined && - _.disconnect(hoverLostConnectionId); - }, + onDestroy: (_) => connections.map(id => _.disconnect(id)), onClick: () => Windows.toggle("center-window"), child: new Widget.Box({ className: "media", children: [ new Widget.Box({ - children: bind(mpris, "players").as((players: Array) => + spacing: 4, + children: bind(AstalMpris.get_default(), "players").as((players: Array) => players[0] ? [ new Widget.Label({ className: "icon nf", @@ -102,9 +95,10 @@ export function Media(): Gtk.Widget { } as Widget.LabelProps), Separator({ orientation: Gtk.Orientation.HORIZONTAL, - size: 2, - cssColor: `rgb(180, 180, 180)`, - alpha: 0.3 + size: 1, + margin: 5, + //cssColor: `rgb(180, 180, 180)`, + alpha: .3 } as SeparatorProps), new Widget.Label({ className: "artist", @@ -122,15 +116,16 @@ export function Media(): Gtk.Widget { } as Widget.BoxProps) } as Widget.EventBoxProps); - hoverConnectionId = mediaWidget.connect("hover", () => { - mediaControlsRevealer.set_reveal_child(true); - mediaWidget.className = mediaWidget.className + " reveal"; - }); - - hoverLostConnectionId = mediaWidget.connect("hover-lost", (_) => { - mediaControlsRevealer.set_reveal_child(false); - _.className = mediaWidget.className.replaceAll(" reveal", ""); - }); + connections.push( + mediaWidget.connect("hover", () => { + mediaControlsRevealer.set_reveal_child(true); + mediaWidget.className = mediaWidget.className + " reveal"; + }), + mediaWidget.connect("hover-lost", (_) => { + mediaControlsRevealer.set_reveal_child(false); + _.className = mediaWidget.className.replaceAll(" reveal", ""); + }) + ); return mediaWidget; } diff --git a/ags/widget/bar/Workspaces.ts b/ags/widget/bar/Workspaces.ts index a4932a9..b2d1434 100644 --- a/ags/widget/bar/Workspaces.ts +++ b/ags/widget/bar/Workspaces.ts @@ -41,7 +41,8 @@ export function Workspaces(): Gtk.Widget { : "" } ${lastClient.title}` : "" }`)(), child: new Widget.Box({ - children: [ + visible: bind(workspace, "lastClient").as(Boolean), + children: bind(workspace, "lastClient").as((lastClient) => [ new Widget.Revealer({ transitionDuration: 200, transitionType: Gtk.RevealerTransitionType.SLIDE_LEFT, @@ -55,17 +56,16 @@ export function Workspaces(): Gtk.Widget { } as Widget.RevealerProps), new Widget.Icon({ className: "last-app-icon", - visible: Variable.derive([ - bind(workspace, "lastClient"), - bind(hyprland, "focusedWorkspace") - ], (lastClient, focusedWorkspace) => focusedWorkspace?.id === workspace.id ? - false : Boolean(lastClient))(), - icon: bind(workspace, "lastClient").as((lastClient) => - lastClient ? - getAppIcon(lastClient.initialClass) || "image-missing" - : "image-missing") - } as Widget.IconProps), - ] + visible: bind(hyprland, "focusedWorkspace").as(focusedWorkspace => + workspace.id === focusedWorkspace.id ? + false + : Boolean(lastClient)), + icon: lastClient ? + bind(lastClient, "class").as((clss) => + getAppIcon(clss) ?? "application-x-executable-symbolic") + : undefined + } as Widget.IconProps) + ]) } as Widget.BoxProps), onClicked: () => workspace.focus() } as Widget.ButtonProps) diff --git a/ags/widget/control-center/pages/Bluetooth.ts b/ags/widget/control-center/pages/Bluetooth.ts index 84ff65a..42b4632 100644 --- a/ags/widget/control-center/pages/Bluetooth.ts +++ b/ags/widget/control-center/pages/Bluetooth.ts @@ -35,11 +35,13 @@ export const BluetoothPage: (() => Page) = () => new Page({ } as Widget.ButtonProps) ], onClose: () => stopBluetoothDevicesWatch(), + spacing: 2, children: [ new Widget.Box({ className: "adapters", visible: bind(AstalBluetooth.get_default(), "adapters").as((adapters) => adapters.length > 1), + spacing: 2, children: bind(AstalBluetooth.get_default(), "adapters").as((adapters) => [ new Widget.Label({ className: "sub-header", @@ -59,6 +61,7 @@ export const BluetoothPage: (() => Page) = () => new Page({ className: "connections", orientation: Gtk.Orientation.VERTICAL, hexpand: true, + spacing: 2, children: [ new Widget.Box({ className: "paired", diff --git a/ags/widget/control-center/pages/Page.ts b/ags/widget/control-center/pages/Page.ts index fc0694b..d106f0b 100644 --- a/ags/widget/control-center/pages/Page.ts +++ b/ags/widget/control-center/pages/Page.ts @@ -11,6 +11,7 @@ export type PageProps = { description?: string | Binding; headerButtons?: Array | Binding>; orientation?: Gtk.Orientation | Binding; + spacing?: number; child?: Gtk.Widget | Binding; children?: Array | Binding>; }; @@ -76,6 +77,7 @@ class Page extends Widget.Box { } as Widget.BoxProps), new Widget.Box({ className: "content", + spacing: props.spacing ?? 4, orientation: props.orientation ?? Gtk.Orientation.VERTICAL, expand: true, setup: props.setup, diff --git a/ags/window/Bar.ts b/ags/window/Bar.ts index 2ecea2b..ed796d9 100644 --- a/ags/window/Bar.ts +++ b/ags/window/Bar.ts @@ -8,6 +8,9 @@ import { Apps } from "../widget/bar/Apps"; import { Clock } from "../widget/bar/Clock"; import { Status } from "../widget/bar/Status"; import { SpecialWorkspaces } from "../widget/bar/SpecialWorkspaces"; +import { Separator, SeparatorProps } from "../widget/Separator"; +import AstalHyprland from "gi://AstalHyprland?version=0.1"; +import { bind } from "astal"; export const Bar = (mon: number) => { const widgetSpacing = 4; @@ -34,6 +37,13 @@ export const Bar = (mon: number) => { children: [ Apps(), SpecialWorkspaces(), + Separator({ + alpha: .2, + orientation: Gtk.Orientation.HORIZONTAL, + margin: 14, + visible: bind(AstalHyprland.get_default(), "workspaces").as(wss => + wss.filter(ws => ws.id < 0).length > 0) + } as SeparatorProps), Workspaces(), FocusedClient() ] diff --git a/ags/window/CenterWindow.ts b/ags/window/CenterWindow.ts index 603d7d7..0a81ff2 100644 --- a/ags/window/CenterWindow.ts +++ b/ags/window/CenterWindow.ts @@ -14,13 +14,14 @@ export const CenterWindow = (mon: number) => PopupWindow({ monitor: mon, child: new Widget.Box({ className: "center-window-container", + spacing: 6, children: [ new Widget.Box({ - className: "vertical left", + className: "left", orientation: Gtk.Orientation.VERTICAL, children: [ new Widget.Box({ - className: "top", + className: "datetime", orientation: Gtk.Orientation.VERTICAL, valign: Gtk.Align.START, children: [ @@ -52,16 +53,12 @@ export const CenterWindow = (mon: number) => PopupWindow({ } as Widget.BoxProps), Separator({ orientation: Gtk.Orientation.HORIZONTAL, - alpha: .5, cssColor: "gray", + margin: 5, + alpha: .3, visible: bind(AstalMpris.get_default(), "players").as(players => players.length > 0), - size: 1 } as SeparatorProps), - new Widget.Box({ - className: "vertical right", - orientation: Gtk.Orientation.VERTICAL, - child: BigMedia() - } as Widget.BoxProps) + BigMedia() ] } as Widget.BoxProps) } as PopupWindowProps);